Java全栈(未完结更新中)
本文最后更新于54 天前,如有错误请发送邮件到guzhougongzuoshi@aliyun.com

java

标识符和关键字

java所有的组成部分都需要名字,类名,方法名,变量名

标识符

标识符要求

  • 所有标识符都应该以字母,$,或者下划线开头
  • 首字符之后可以时字母,$,下划线或者数字的任何字符组合
  • 不能使用关键字作为变量名或者类名、方法名
  • 区分大小写
  • 不建议用中文拼音命名或者中文

数据类型

强类型语言

即对于变量的使用严格规定,所有变量必须先定义后才能使用
比如说:java,C,C++

弱类型语言

比如说:JavaScript

java的数据类型

分为:

  • 基本类型 primitive type
  • 引用类型 reference type

基本类型

  • 整数类型
    • byte 占用一个字节
    • short 占用两个字节
    • int 占用四个字节
    • long 占用8个字节
      • 在定义long类型时会在数字后加“L”
      • 比如:long num = 3000L;
  • 浮点类型
    • float 占用4字节
      • 在定义float类型时要在数字后面加“F”
      • 比如:float num = 12.32F;
        >注意:float浮点数是有限的离散的,会存在误差,最好完全避免使用浮点数进行比较,可以使用BigDecimal类
    • double 占用8字节
  • 字符类型
    • char 占用2字节
      • 使用时用”单引号
      • 区别于String的字符串,而且String是类而不是关键字
      • 所有字符本质都是数字(Unicode编码)因此可以强制转换为整型
        java char c = 'c'; System.out.println((int)c);//强制转换
  • 布尔值类型
    • boolean
      • 只有两个结果:true | false

引用类型

  • 接口
  • 数组

进制问题

  • 二进制:开头0b
  • 十进制:默认
  • 八进制:开头0
  • 十六进制:开头0x

转义字符

转义字符实义
\t制表符(相当于键盘tab键)
\n换行
\r回车
\b退格(删除光标之前的一个字符)
\\ (反斜杠)用于表示反斜杠字符(\),因为反斜杠本身是转义字符的起始符号,所以需要双反斜杠来表示一个反斜杠。
\’ (单引号)用于在字符串或字符中表示单引号。
\” (双引号)用于在字符串中表示双引号

类型转换

由于java是强类型语言,运算中,不同类型的数据先转换为同一类型,然后进行运算。
低——————————-高
byte -short- char – int – float – long – double

强制转换

从高容量到低容量:必须强制转换

int i = 12;
byte b = (byte)i;//强制类型转换
  • 注意无法转换布尔类型
  • 不能将对象类型转换为不相干的类型
  • 转换时可能存在内存溢出或者精度缺失

自动转换

当低容量到高容量转换时:无需任何操作

变量

变量即可以变的量

  • 每个变量都要声明类型,类型可以时基本类型也可以是引用类型
  • 变量名必须以合法的变量名声明命名
  • 变量声明必须以英文输入法下分号结束
int a;
int a,b,c;//合法但不建议,可读性很差
int a=1,b=2,c=3;//合法但不建议

变量作用域

类变量:

使用static声明的变量

  • 作用域:类变量在整个类的所有实例中共享。换句话说,不管你创建了多少个对象,类变量都是唯一的,所有对象都共享同一个变量
public class Person_static {
    static int count =0;//类变量

    public static void main(String[] args) {
        System.out.println(count);
    }
}

实例变量:

写在类里面的变量

  • 从属于对象
  • 若没有初始化,会默认保存初始值0或0.0(布尔值默认false)除了基本类型其他都是null
public class Person_static {
    public String name;//实例变量
public Person_static(String name){
    this.name = name;
}

    public static void main(String[] args) {
    Person_static p1 =new Person_static("lihan");
        System.out.println(p1.name);
    }
}

局部变量:

写在方法内的变量

  • 局部变量使用前必须声明且同时初始化值
  • 局部变量只在方法中生效
  • 属于方法或代码块,仅在方法或代码块中有效,生命周期很短,随方法执行完毕而消失。
public void method(){  
    int i = 0; //局部变量
}

常量

常量:初始化后不能更改,可以理解为一种不能修改的特殊变量
使用final关键字声明

  • 常量名用大写
final int P = 3;

命名规范

所有命名都要求见名知义

  • 类成员变量:首字母小写+驼峰命名法
  • 局部变量:首字母小写+驼峰命名法
  • 常量:大写字母和下划线
  • 类名:首字母大写+驼峰命名法
  • 方法名:首字母小写+驼峰命名法

运算符

  • 算数运算符
  • 赋值运算符
  • 关系运算符
  • 逻辑运算符
  • 位运算符
  • 条件运算符
  • 扩展赋值运算符

子运算++ —

(一元运算符)

  • 自增:++
  • 自减:–
 int a = 1;
        int b = ++a;  //先执行a=a+1的指令,再将结果赋值给b
    /*等效于:
    a = a + 1;
    b =a;
     */
        int c = a++;  //先将a原来的值赋值给c,再执行a=a+1;
    /*等效于:
    c = a;
    a = a + 1;
     */

幂运算

Math.pow(2,3) //2的3次方

        double pow = Math.pow(2,3);
        System.out.println(pow);

运行结果:8.0

位运算符

    public static void main(String[] args) {
        // 与 &&
        // 或 ||
        // 非 !
        boolean a = true;
        boolean b = false;
        System.out.println("a && b:"+(a&&b));  //逻辑与:两个变量都为真,结果才为真
        System.out.println("a || b:"+(a||b));  //逻辑或:两个变量有一个真,结果才为真
        System.out.println("!(a && b):"+!(a&&b)); //若是真则变假,若是假则变真
        //短路运算:若逻辑运算时前面就可以判断整个式子的真假,则不会运算后面的部分
    }

字符串连接符

在 Java 中,+ 运算符有两种作用:

  • 数值加法:如果 + 的两边都是数值类型(如 int、double 等),那么 + 会执行数学加法。
  • 字符串拼接:如果 + 的一边是字符串(String),Java 会将另一边的数值类型转换为字符串,然后进行字符串拼接。
    public static void main(String[] args) {
        int a = 10;
        int b = 10;
        System.out.println(""+a+b);
        System.out.println(a+b+"");
    }

运行结果:
1010
20

在表达式中,+ 运算符的执行顺序是从左到右的。所以不同的顺序会影响结果。😊😊😊
在示例中:
“” + a + b:因为一开始就有字符串 “”,所以 a 和 b 都会被转换成字符串进行拼接。
a + b +“”:这里 a 和 b 首先是数值相加,得到 20,然后再和空字符串拼接,得到 “20”。

三元运算符

格式:
x ? y : z ;
如果x == true;则结果为y,否则结果为z。

# Java_ScannerOI
Java 流程控制
## 用户交互Scanner对象 {id="scanner_1"}

### Scanner对象
Java提供的可以获取用户输入的工具类,java.util.Scanner是java5新特征
```java
public class Demo01{
public static void main(String[] args){
Scanner scanner = new Scanner(System.in);
System.out.println("使用next方式接收:");

//判断用户有没有输入字符串
if(scanner.hasNext()){
String str = scanner.next();
System.out.println("输出的内容:"+str);
}
scanner.close();
//凡是属于IO流的类如果不关闭会一直占用资源,要养成
}
}
```
基本语法:
```java
Scanner scanner = new Scanner(System.in);
```

Scanner对象:<br>
1. next()
功能:用于读取并返回下一个有效的输入字符或字符串,自动跳过无效字符。
特点:
自动跳过空白字符:next()在读取到有效字符前,会自动跳过空白字符(如空格、换行等)。
有效字符为界:只有在读取到有效字符后,next()才会将后续的空白字符视为分隔符或结束符。
不读取空格:next()无法获取带有空格的字符串,一旦遇到空格就会将其作为分隔符。
2. nextLine()
功能:读取一整行输入,直到用户按下 "Enter" 键为止。
特点:
整行读取:nextLine()会读取包括空格在内的整行内容,并将光标移至下一行等待输入。
以Enter结束:在遇到"Enter"之前的所有字符都被视为有效输入。
3. nextInt()
功能:用于接收整型(int)数据的输入。
特点:
如果输入不为有效的整数值,程序可能会抛出异常。
4. nextDouble()
功能:用于接收双精度浮点型(double)数据的输入。
特点:
输入不为有效的双精度浮点数时,同样会抛出异常。
5. nextFloat()
功能:用于接收单精度浮点型(float)数据的输入。
特点:
与nextDouble()类似,专门用于处理float类型输入。
6. nextShout()
功能:用于接收shout类型数据的输入(假设这是自定义类型)。
特点:根据上下文可能是一个特别定义的类型,需要具体环境下的说明。
7. hasNextInt()
功能:判断是否存在可以解析为int类型的输入。
特点:如果输入内容能够成功转换为int类型,则返回true。
8. hasNext()
功能:判断输入流中是否存在下一个有效的字符或字符串。
特点:常用于输入是否结束的检测。
9. hasNextLine()
功能:判断输入流中是否还有下一行内容可供读取。
特点:通常用于检测输入是否已读到最后一行。
10. hasNextDouble()
功能:判断是否存在可以解析为double类型的数据。
特点:如果输入内容能被成功解析为double类型,则返回true。
11. hasNextFloat()
功能:判断是否存在可以解析为float类型的数据。
特点:与hasNextDouble()类似,用于检测float类型的数据输入。
12. hasNextShout()
功能:判断是否存在可以解析为shout类型的数据(假设为自定义类型)。
特点:具体行为需参考shout类型的定义。

# Java_三大结构
## Java的基本控制结构

### 顺序结构
在Java编程中,最基本的结构就是顺序结构。**顺序结构**指的是代码按照书写顺序,从上到下依次执行,除非遇到跳转、选择或循环等结构。顺序结构是所有程序的基础,也是默认的执行方式。

例如:
```Java
System.out.println("开始程序"); // 这行代码会先执行
System.out.println("执行代码块"); // 然后执行这一行
System.out.println("程序结束"); // 最后执行这一行
```

### 选择结构
选择结构是一种根据条件判断执行不同代码块的结构。Java中常见的选择结构包括 `if` 语句和 `switch` 语句。

#### if 单选择结构 {id="if_1"}
单选择结构是最简单的条件判断结构,根据一个条件是否成立来决定是否执行代码块。

语法:
```Java
if(条件){
// 当条件为 true 时执行这段代码
}
```

示例:
```Java
int number = 5;
if(number > 3){
System.out.println("数字大于3");
}
```
在这个例子中,如果 `number` 大于3,程序就会打印 "数字大于3"。

#### if 双选择结构 {id="if_2"}
双选择结构不仅在条件成立时执行代码,还会在条件不成立时执行另一段代码。

语法:
```Java
if(条件){
// 当条件为 true 时执行这段代码
} else {
// 当条件为 false 时执行这段代码
}
```

示例:
```Java
int number = 2;
if(number > 3){
System.out.println("数字大于3");
} else {
System.out.println("数字小于或等于3");
}
```
在这个例子中,程序会打印 "数字小于或等于3"。

#### if 多选择结构
如果有多个条件需要判断,使用 `if-else if` 语句。程序会从上到下依次判断条件,直到某个条件为 `true` 执行对应代码块,或者执行最后的 `else` 块。

语法:
```Java
if(条件1){
// 条件1为 true 时执行
} else if(条件2){
// 条件2为 true 时执行
} else if(条件n){
// 条件n为 true 时执行
} else {
// 当所有条件都不满足时执行
}
```

示例:
```Java
int score = 85;
if(score >= 90){
System.out.println("优秀");
} else if(score >= 80){
System.out.println("良好");
} else if(score >= 70){
System.out.println("合格");
} else {
System.out.println("不合格");
}
```
程序会根据 `score` 的值打印相应的等级。

#### 嵌套if语句 {id="if_3"}
`if` 语句是可以嵌套的,即在一个 `if` 语句内部再使用 `if` 或 `if-else` 结构。当逻辑较为复杂时,可以通过嵌套 `if` 语句处理。

语法:
```Java
if(条件1){
if(条件2){
// 条件1和条件2都为 true 时执行
} else {
// 条件1为 true 且条件2为 false 时执行
}
} else {
// 条件1为 false 时执行
}
```

示例:
```Java
int age = 20;
int height = 180;
if(age > 18){
if(height > 170){
System.out.println("成年且身高大于170cm");
} else {
System.out.println("成年但身高小于或等于170cm");
}
} else {
System.out.println("未成年");
}
```
在这个例子中,程序会检查年龄是否大于18岁,然后再检查身高是否大于170cm。根据不同的条件,程序会打印不同的结果。

#### switch 多选择结构
多选择结构还有一个实现方式:`switch` `case` 语句。
`switch` 语句用于判断一个变量的值,并根据这个值与多个 `case` 分支的匹配情况执行对应的代码。

语法格式:
```Java
char grade = 'C';
switch (grade) {
case 'A':
System.out.println("优秀");
break;
case 'B':
System.out.println("良好");
break;
case 'C':
System.out.println("及格");
break;
case 'D':
System.out.println("不及格");
break;
default:
System.out.println("输入错误");
}
```
- `break` 的作用:中止当前 `case` 分支的执行,防止程序执行下一个 `case` 语句,也就是防止“穿透”。如果没有 `break`,程序会继续执行下一个 `case`,即使它不满足条件。
- `default` 的作用:当所有 `case` 分支都不匹配时,执行 `default` 代码块,类似于 `else` 语句。

**额外提示**:
- 从JDK 7开始,`switch` 语句支持 `String` 类型的变量,这使得在处理字符串时更加方便。

---

### 循环结构

#### while 循环
`while` 循环是Java中最基本的循环结构之一,用于在布尔表达式为 `true` 的情况下反复执行代码块。

语法格式:
```java
while(布尔表达式){
// 循环体
}
```
只要布尔表达式的结果为 `true`,循环体就会被反复执行。因此,通常需要在循环体内修改控制条件以避免无限循环。

```java
// 示例:计算1到100的和
int i = 0;
int sum = 0;
while (i <= 100) {
sum += i;
i++;
}
System.out.println(sum); // 输出:5050
```

**死循环**:`while (true)` 表示一个永远不会结束的循环,通常在某些情况下会用到,例如:
```java
while (true) {
// 这是一种死循环,通常用于:
// 1. 等待客户端连接
// 2. 定期检查任务
// 但要避免在正常开发中使用这种循环,因为它会导致程序无法结束。
break; // 可以使用 break 语句来终止死循环
}
```

---

#### do-while 循环
`do-while` 循环与 `while` 循环的区别在于,它会**先执行一次循环体**,然后再判断条件是否成立。即使条件为 `false`,循环体也会至少执行一次。

语法格式:
```java
do {
// 循环体
} while(布尔表达式);
```

---

### For 循环
`for` 循环是Java中最常用的循环结构之一,因为它结构紧凑、可读性强,特别适合在已知循环次数的情况下使用。

语法格式:
```java
for(初始化; 布尔表达式; 迭代) {
// 循环体
}
```

以下是 `while` 循环和 `for` 循环的等效例子:
```java
// while 循环
int a = 1;
while (a <= 100) {
System.out.println(a);
a += 5; // 迭代
}
System.out.println("while 循环结束");

// for 循环
for (int i = 1; i <= 100; i += 5) {
System.out.println(i);
}
System.out.println("for 循环结束");
```

**`for` 循环的优势**:
- 初始化部分在循环开始时只执行一次。
- 布尔表达式在每次循环前进行判断,如果为 `true`,则执行循环体;如果为 `false`,循环结束。
- 迭代部分在每次循环结束后执行,可以用来控制循环的变化。

---

### 增强for循环 {id="for_1"}
增强 `for` 循环是JDK 5引入的一种简化数组或集合遍历的方式,适用于遍历所有元素,而不需要使用索引来访问元素。

**语法格式**:
```java
for(元素类型 变量名 : 集合或数组) {
// 循环体
}
```
在增强 `for` 循环中,**每次迭代会将数组或集合中的一个元素赋值给变量**,并执行循环体。

例如,下面的代码遍历并输出一个数组中的每个元素:
```java
public class ScannerForPRO {
public static void main(String[] args) {
int[] numbers = {10, 20, 30, 40, 50}; // 定义了一个数组
for (int x : numbers) {
System.out.println(x); // 依次输出数组中的每个元素
}
}
}
```

上述代码的等效传统 `for` 循环:
```java
for (int i = 0; i < numbers.length; i++) {
System.out.println(numbers[i]);
}
```

**增强 `for` 循环的原理**:
- 它的作用类似于遍历数组中的每个元素,并将当前遍历到的元素赋值给变量 `x`。每次循环 `x` 会依次获取数组中的下一个元素。
- 增强 `for` 循环适合用于**遍历数组或集合**,而不需要关心索引或者手动控制循环。

**优点**:
- 增强 `for` 循环更加简洁易读,特别适用于只需要遍历数组或集合时。
- 省去了手动控制循环变量和索引的复杂操作。



## break 和 continue 关键词
### break
- break 在任何循环的主体部分,都可以控制循环流程。
- break 用于**强制退出循环**,不执行循环中剩余的语句
- break 也用在switch语句中

### continue
- continue 用于循环语句体中,用于**中止某次循环过程**,即跳过循环体中尚未执行的语句,接着进行下一次判断是否执行下一次循环的判定。

### goto
- goto 虽然很早就在程序设计语言中出现,尽管goto仍然是java的一个保留字,但并未在语言中得到正式使用。
- java中没有goto






# Java_方法

## 什么是方法
在Java中,方法是一组用于执行某一特定功能的代码片段。比如 `System.out.println()`,其中 `System` 是一个类,`out` 是 `System` 类的一个对象,而 `println` 就是一个方法。方法可以让代码更加模块化,便于复用和维护。

Java中的**方法**可以理解为一系列语句的集合,用来实现某个功能。方法的设计原则如下:
- 方法的本意是功能块,表示实现某一特定功能的代码块。
- 一个方法应该只完成一个功能,这样可以提高代码的可维护性和可扩展性。
- 方法必须包含在类或对象中。
- 命名规则:方法名应以小写字母开头,使用驼峰命名法(例如 `calculateSum`)。
- `main()` 方法要尽量保持简洁明了。

例如:
```java
public class LearnMethod01 {
public static void main(String[] args) {
int sum = add(1, 2);
System.out.println(sum);
}

// 定义一个求和的方法
public static int add(int a, int b) {
return a + b;
}
}
```

---

## 方法的定义
在Java中,方法类似于其他编程语言中的函数,是一段用于完成特定功能的代码片段。定义一个方法的基本语法如下:
```java
修饰符 返回值类型 方法名(参数类型 参数名) {
方法体
return 返回值;
}
```
- **方法头**:包含修饰符、返回值类型、方法名和参数列表。
- **修饰符**:可选,通常用于指定方法的访问权限(如 `public`、`private` 等)。
- **返回值类型**:方法的返回类型,若没有返回值则用 `void` 表示。
- **方法名**:定义方法的名称,通常遵循驼峰命名法。
- **参数类型和参数名**:指定方法接受的参数类型和名称,参数名用于方法内部使用。
- **方法体**:包含具体的代码,用于实现方法的功能。
- **返回值**:通过 `return` 语句返回结果,若方法无返回值则不需要 `return`。

例如:
```java
public static int max(int a, int b) {
if (a == b) {
return 0; // 返回0,并且终止方法的执行
}
return (a > b) ? a : b; // 返回较大的值
}
```

---

## 方法重载
**方法重载**是指在同一个类中可以定义多个相同名称的方法,只要它们的参数列表不同即可。方法重载的主要规则是:
- 方法名必须相同。
- 参数列表必须不同(参数的类型、个数、顺序之一不同)。
- 方法的返回类型可以相同或不同,但返回类型不能作为重载的唯一依据。

例如:
```java
public static int add(int a, int b) {
return a + b;
}

public static double add(double a, double b) {
return a + b;
}
```
在上面的例子中,`add` 方法被重载了两次,分别用于处理整数和浮点数的加法运算。

---

## 命令行传参
(了解即可)在运行一个Java程序时,可以通过命令行参数将数据传递给 `main()` 方法。`main()` 方法的参数是一个字符串数组,用来接收命令行传入的参数。

---

## 可变传参
从JDK 1.5开始,Java支持在方法中使用可变长度参数。可变参数允许你传递任意数量的同类型参数给方法。
- 可变参数通过在参数类型后面加 `...` 表示。
- 一个方法只能有一个可变参数,且该参数必须是方法的最后一个参数。

例如:
```java
public static void printNumbers(int... numbers) {
for (int number : numbers) {
System.out.println(number);
}
}
```
调用该方法时可以传入任意数量的整数:
```java
printNumbers(1, 2, 3, 4); // 输出1到4
```

---

## 递归
**递归**指的是一个方法调用自身。递归通常用于解决那些可以通过将问题分解为更小的相同问题来处理的场景。递归的核心思想是将复杂问题转化为更简单的问题层层求解。

递归方法通常包括两部分:
1. **递归头**:终止递归的条件。如果没有递归头,递归将一直执行下去,导致栈溢出。
2. **递归体**:包含调用自身的部分。

递归的优点是可以用简洁的代码实现复杂的逻辑,但递归深度过大可能会导致栈内存不足,出现栈溢出问题。

一个经典的递归例子是计算阶乘:
```java
public static int factorial(int n) {
if (n == 1) { // 递归头,终止递归的条件
return 1;
} else {
return n * factorial(n - 1); // 递归体,调用自身
}
}
```
在这个例子中,`factorial(5)` 会递归调用自身,直到 `n == 1`,最后返回阶乘的结果。递归的调用链如下:
```
factorial(5) = 5 * factorial(4)
factorial(4) = 4 * factorial(3)
factorial(3) = 3 * factorial(2)
factorial(2) = 2 * factorial(1)
factorial(1) = 1
```
因此,`factorial(5)` 的结果为 `5 * 4 * 3 * 2 * 1 = 120`。

递归虽然强大,但如果递归层数过深,可能会导致栈溢出(即内存不足来存储递归调用),所以递归策略适合处理规模较小的问题。

---
# Java_数组

## 数组的定义
- **数组**是相同类型数据的有序集合。
- 数组是由若干相同类型的数据组成的,这些数据按照一定的顺序排列组合。
- 数组中的每一个数据叫做**数组元素**,每个数组元素可以通过**下标**来访问。

## 数组的声明
在使用数组之前,必须先声明数组变量。
语法格式:

```java
dataType[] arrayRefVar; // 推荐的声明方式
int[] nums; // 声明一个名为 nums 的 int 类型数组

dataType arrayRefVar[]; // 也可以用这种方式,但不推荐
int nums2[]; // 与上面 nums 效果相同
```

### 数组的创建
在 Java 中,使用 `new` 操作符来创建数组。

```java
dataType[] arrayRefVar = new dataType[arraySize];
int[] nums3 = new int[10]; // 创建了一个名为 nums3 的长度为10的int数组
```

- `int[] nums3 = new int[10];` 定义了一个名为 `nums3` 的 int 类型数组,并通过 `new` 操作符为数组分配内存。这个数组可以存放 10 个整数元素,数组的索引从 `0` 到 `9`。

### 访问数组元素
数组的元素是通过**索引**访问的,索引从 `0` 开始。
获取数组长度的语法:`array.length`。

## Java内存分析 {id="java_1"}
在 Java 中,内存主要分为三个区域:堆、栈和方法区。

### 堆(Heap)
- 存放通过 `new` 操作符创建的对象和数组。
- 堆内存是所有线程共享的,不会存放局部变量。

### 栈(Stack)
- 存放基本类型变量(包含基本类型的具体数值)。
- 存放引用对象的变量(引用的对象存放在堆中)。

### 方法区(Method Area)
- 被所有线程共享,存放类的相关信息和 `static` 变量。

## Java数组的三种初始化

1. **动态初始化**:指定数组长度,由系统自动初始化。
```java
int[] nums = new int[10]; // 动态初始化,长度为10,元素自动初始化为 0
```
2. **静态初始化**:在定义数组时直接为每个元素赋值。
```java
int[] nums = {1, 2, 3, 4, 5}; // 静态初始化
```
3. **默认初始化**:数组创建时,元素默认被初始化(int 类型默认为 0,引用类型默认为 `null`)。

## 数组的四个基本特点
1. **长度固定**:数组一旦被创建,大小不可改变。
2. **相同类型**:数组中的元素必须是相同类型的,不允许出现混合类型。
3. **元素类型多样**:数组中的元素可以是任何类型的数据,包括基本类型和引用类型。
4. **引用类型**:数组变量是引用类型,数组可以看作对象,数组中的每个元素相当于该对象的成员变量。数组本身在堆中分配空间。

## 多维数组
**多维数组**可以看作是数组的数组,例如二维数组是一个特殊的一维数组,其每个元素又是一个一维数组。

```java
int[][] a = new int[2][5]; // 创建了一个2行5列的二维数组
```

## 冒泡排序

冒泡排序是一种简单的排序算法,基本原理是通过比较相邻的元素来把最大的元素逐步“冒泡”到数组的末尾。

### 冒泡排序步骤:
1. 比较相邻的元素,如果前面的比后面的元素大,则交换它们。
2. 重复相邻元素的比较和交换,直到数组的末尾,此时最大的元素会被排到数组的最后。
3. 再次从头开始,继续对剩下的部分进行同样的操作。
4. 这个过程会不断重复,直到整个数组有序。

### 冒泡排序的代码实现:

```java
public int[] bubbleSort(int[] array) {
int temp;
boolean swapped;
for (int i = 0; i < array.length - 1; i++) {
swapped = false; // 每轮开始前初始化为false
for (int j = 0; j < array.length - 1 - i; j++) {
if (array[j] > array[j + 1]) { // 如果前一个元素大于后一个元素
temp = array[j]; // 交换两者
array[j] = array[j + 1];
array[j + 1] = temp;
swapped = true; // 发生交换,标记为true
}
}
if (!swapped) { // 如果在一轮中没有发生交换,说明数组已排序完成
break;
}
}
return array;
}
```

### 冒泡排序的解释:
- 外层循环:控制排序的轮数,每轮都会把当前最大值“冒泡”到数组的尾部。
- 内层循环:比较相邻的元素并进行交换。
- `swapped` 标志:用于优化,如果某一轮没有发生交换,则说明数组已经有序,可以提前终止排序。

## 稀疏数组

### 什么是稀疏数组?
稀疏数组是指其中大多数元素都是相同值(通常是 0)的数组。与普通数组不同,稀疏数组可以通过压缩存储来节省空间,只记录非默认值的元素及其位置信息。

### 稀疏数组的使用场景:
当一个数组的大多数元素为相同的值时(例如:0),使用稀疏数组能够有效地减少空间占用,提升程序性能。

### 稀疏数组的转换过程:
1. **记录原始数组的行数、列数和非零元素的个数**。
2. **记录非零元素的位置(行和列)及其值**。
3. 将这些信息存储到一个新的稀疏数组中,原数组可以通过该稀疏数组还原。

### 稀疏数组的代码实现:
```java
public class SparseArray {
public static void main(String[] args) {
// 原始二维数组,0 表示没有元素,1 表示有元素
int[][] originalArray = new int[11][11];
originalArray[1][2] = 1;
originalArray[2][3] = 2;

// 统计非零值个数
int nonZeroCount = 0;
for (int i = 0; i < 11; i++) {
for (int j = 0; j < 11; j++) {
if (originalArray[i][j] != 0) {
nonZeroCount++;
}
}
}

// 创建稀疏数组
int[][] sparseArray = new int[nonZeroCount + 1][3];
sparseArray[0][0] = 11; // 原数组的行数
sparseArray[0][1] = 11; // 原数组的列数
sparseArray[0][2] = nonZeroCount; // 非零元素的个数

// 将非零值存入稀疏数组
int count = 0;
for (int i = 0; i < 11; i++) {
for (int j = 0; j < 11; j++) {
if (originalArray[i][j] != 0) {
count++;
sparseArray[count][0] = i;
sparseArray[count][1] = j;
sparseArray[count][2] = originalArray[i][j];
}
}
}

// 输出稀疏数组
System.out.println("稀疏数组:");
for (int i = 0; i < sparseArray.length; i++) {
System.out.printf("%d\t%d\t%d\n", sparseArray[i][0], sparseArray[i][1], sparseArray[i][2]);
}

// 恢复二维数组
int[][] restoredArray = new int[sparseArray[0][0]][sparseArray[0][1]];
for (int i = 1; i < sparseArray.length; i++) {
restoredArray[sparseArray[i][0]][sparseArray[i][1]] = sparseArray[i][2];
}
}
}
```

### 稀疏数组的解释:
- **稀疏数组格式**:第一行记录原始数组的大小(行和列)以及非零元素的个数,后面的每一行记录非零元素的行、列和值。
- **优势**:通过这种方式,原本占用大量空间的数组可以转化为一个较小的稀疏数组,极大地节省空间。

## 总结
- 数组是存储相同类型元素的有序

集合,可以通过下标访问元素,长度固定。
- Java 中数组是引用类型,保存在堆内存中。
- 冒泡排序是一种通过相邻元素比较并交换来排序的简单算法。
- 稀疏数组适用于大多数元素相同(如 0)的场景,能够压缩存储,减少空间占用。
# Java_OOP

面向对象编程(OOP)是一种编程范式,通过将数据和操作数据的代码组织成对象,使得代码结构更加清晰、易维护。Java 是一种典型的面向对象语言。以下是 Java 面向对象编程的主要概念和特性。

## 面向过程和面向对象

### 面向过程
- **面向过程**是一种编程方式,注重按步骤执行代码来完成任务,每一步都是按顺序处理的。
- 适合一些简单、短小的程序,但当程序规模增大时,代码复用性和可维护性较差。

### 面向对象
- **面向对象**是一种将程序结构按对象(事物的抽象)来组织的编程方式,通过类与对象的方式进行程序设计。
- **面向对象的本质**:通过类的方式组织代码,使用对象来封装数据。
- **核心思想**:抽象,把现实中的事物抽象为对象和类。

#### 三大特性
1. **封装**:将对象的状态信息隐藏在内部,仅提供公共方法供外部调用。
2. **继承**:通过继承机制,子类可以继承父类的属性和方法,减少代码重复。
3. **多态**:同一方法在不同对象中可以有不同表现,增强代码的灵活性和扩展性。

## 静态类和非静态类

### 静态类
- 在 Java 中,**静态类**一般指嵌套在其他类中的 `static` 内部类。
- 静态类可以直接通过外部类调用,不需要实例化外部类。

### 非静态类
- **非静态类**必须实例化后才能使用。
- 例如:
```java
Student student = new Student(); // 创建 Student 类的实例
```

## 形参和实参

- **形参**:方法定义时的参数,称为形式参数。
- **实参**:调用方法时实际传入的参数,称为实际参数。

## 值传递和引用传递

- **值传递**:传递基本类型的值,不影响原始数据。
- **引用传递**:传递对象引用,对象的属性值可能被改变。

## `this` 关键字

- **`this`** 代表当前对象的引用,用于区分成员变量和局部变量,也可以在构造方法中调用类的其他构造方法。

## 类和对象的关系
- **类**是一种抽象的数据类型,是对某一类事物的整体描述。
- **对象**是类的实例化,即具体的实例,代表某一类事物的具体表现。

## 构造器(构造方法)

### 构造器的作用
1. 在创建对象时初始化对象的属性。
2. 使用 `new` 关键字创建对象时必须调用构造器。

### 构造器的特点
1. 构造器的名称与类名相同。
2. 构造器没有返回值类型。
3. 如果定义了带参数的构造器,需要额外定义无参构造器以确保兼容性。

### 快捷键
- 在 IDE 中使用 `Alt+Insert` 快速生成构造器。

```java
public class Student {
private String name;
private int age;

public Student(String name, int age) { // 带参构造器
this.name = name;
this.age = age;
}
}
```

## 创建对象的内存分析

Java 内存分为堆、栈、方法区等部分,不同数据存放在不同区域。创建对象时,对象存放在堆中,对象的引用存放在栈中。

## 封装

- **封装**是一种将数据隐藏在对象内部的方式,通过 `private` 关键字对属性进行封装,外部只能通过 `get` 和 `set` 方法访问。

### 封装的意义
1. 提高程序的安全性,保护数据。
2. 隐藏实现细节,减少耦合。
3. 统一接口,增加系统的可维护性。

```java
public class Student {
private String name; // 属性封装
private int age;

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}
}
```

## 继承

- **继承**是一种类与类之间的关系,使得子类可以拥有父类的属性和方法。
- Java 中支持**单继承**,即每个类只能有一个直接父类。

### `extends` 关键字
- 使用 `extends` 关键字表示继承。

```java
public class Animal {
public void eat() {
System.out.println("Animal is eating");
}
}

public class Dog extends Animal {
public void bark() {
System.out.println("Dog is barking");
}
}
```

## 修饰符

- **`public`**:可以被所有类访问。
- **`protected`**:可以被同包和子类访问。
- **默认(default)**:仅限于同包访问。
- **`private`**:仅限于同类访问。

## `Object` 类

- **`Object`** 是所有类的父类,位于 `java.lang` 包中。
- 每个类都隐式继承 `Object` 类,提供基础方法如 `toString()` 和 `equals()`。

## `super` 关键字

- `super` 用于引用父类的属性和方法。
- 在子类构造方法中可以通过 `super()` 调用父类的构造方法,必须位于构造方法的首行。

### `super` 与 `this` 的区别
- **`this`**:代表当前对象的引用。
- **`super`**:代表父类对象的引用。
- **构造方法**:
- `this()` 调用当前类的构造方法。
- `super()` 调用父类的构造方法。

## 方法的重写

- **重写**是子类对父类方法进行修改,满足多态性需求。
- 使用 `@Override` 注解标注重写的方法,确保语法正确。

### 重写的规则
1. 方法名和参数列表必须相同。
2. 访问权限范围可以扩大但不能缩小。
3. 抛出异常范围可以缩小但不能扩大。

```java
public class Animal {
public void sound() {
System.out.println("Animal makes sound");
}
}

public class Dog extends Animal {
@Override
public void sound() {
System.out.println("Dog barks");
}
}
```

## 多态

- **多态**是指相同的方法可以根据不同对象表现出不同的行为。
- **实现多态的条件**:
1. 存在父子类关系。
2. 子类重写父类方法。
3. 使用父类引用指向子类对象。

```java
public class Animal {
public void sound() {
System.out.println("Animal sound");
}
}

public class Dog extends Animal {
@Override
public void sound() {
System.out.println("Dog barks");
}
}

Animal animal = new Dog();
animal.sound(); // 输出: Dog barks
```

## `instanceof` 关键字和引用类型的转换

- **`instanceof`** 检查一个对象是否是某个类或接口的实例,用于避免类型转换异常。
- **类型转换**:
1. 父类引用指向子类对象(向上转型),自动转换。
2. 父类引用转回子类对象(向下转型),需要强制转换。

```java
Animal animal = new Dog();
if (animal instanceof Dog) {
Dog dog = (Dog) animal;
dog.bark();
}
```

## `static` 关键字

- **`static`** 表示静态成员或方法,属于类本身,不依赖于具体对象。
- **静态代码块**:只在类加载时执行一次,用于初始化类的静态资源。

```java
public class StaticExample {
static {
System.out.println("Static block");
}

{
System.out.println("Instance block");
}

public StaticExample() {
System.out.println("Constructor");
}

public static void main(String[] args) {
new StaticExample();
new StaticExample();
}
}
```

### 输出结果
```
Static block
Instance block
Constructor
Instance block
Constructor
```

## `final` 关键字

- **`final`** 用于声明常量、方法不可被重写、类不可被继承等情况。

```java
public final class Constants {
public static final int MAX_VALUE = 100;
}
```
感谢您的阅读
暂无评论

发送评论 编辑评论

|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇