当前位置: 首页 > news >正文

java详细笔记总结持续完善

一.Java开发环境的搭建

1. 单位换算

1TB = 1024GB

1GB = 1024MB

1MB = 1024KB

1KB = 1024Byte (字节)

1Byte = 8 bit(位)

注意:一个字节占8位

2. DOS命令

DOS : Disk Operation System 磁盘操作系统 即用于操作本地磁盘的系统

命令操作符号
盘符切换命令盘符名:
查看当前文件夹内容dir
进入文件夹命令cd 文件夹名
退出文件夹命令cd ..
退出到磁盘根目录cd \
清屏cls
退出exit

3. 名词解释

  • JVM(Java Virtual Machine ): Java虚拟机 JVM相当于一个软件 在不同的平台模拟相同的环境 以实现跨平台的效果

  • JRE(Java Runtime Environment) : Java运行环境,包含JVM 和运行时所需要的核心类库

  • JDK(Java Development Kit) : Java开发工具包 ,包含JRE 和开发人员使用的工具。

三者关系:JDK包含 JRE JRE包含JVM

4. 安装JDK

5.配置环境变量

右键此电脑===》高级系统设置===》高级====》环境变量

系统变量====》新建变量

名:JAVA_HOME

值: C:\Program Files\Java\jdk1.8.0_131

找到Path变量===》编辑 ====》新建

直接写值:%JAVA_HOME%\bin

所有已打开的窗口全部确定即可

用户变量 vs 系统变量

用户变量 :当前用户自己独有的变量,切换到其他用户后就不能使用来了

系统变量:当前系统中,所有的用户都共享的变量

6.测试

徽标 + R 输入 CMD

javac -version

java -version

以上两个命令都出现版本号表示安装JDK并且环境变量配置成功

7.关于配置环境变量问题补充

1.为什么不直接在Path变量中配置C:\Program Files\Java\jdk1.8.0_131\bin

直接在Path变量中写为C:\Program Files\Java\jdk1.8.0_131\bin 这样的格式目前也是没有问题的 也可以使用

但是后续我们使用的一些工具将默认查找JAVA_HOME变量 比如 tomcat maven等等

2.为什么要配置环境变量?

配置环境变量相当于把bin目录下的命令通知给操作系统 便于我们使用当前目录下对应的命令

3.为什么不配置classpath ?

classpath表示类路径 (即JVM加载类会寻找的路径)

早期(JDK1.5之前)的JDK都需要配置此环境变量 从JDK1.5开始 不需要人为的配置此变量

如果配置了,一定删掉!!!

二.第一个Java程序

2.1 源代码

public class HelloWorld{
    public static void main(String [] args){ 
        System.out.print("hello world 0724");
    }
}

2.2 单词解释

public 公开的

class 类

static 静态的

void 无效的 空的

main 主要的

String 字符串

args arguments 参数 复数形式

System 系统

out 出

print 打印

2.3 注意事项

1.文件名必须与类名完全保持一致 包括大小写

2.注意单词大小写

3.代码中的标点符号默认都是英文模式的

4.注意合适的缩进 每遇到一个大括号就缩进一个tab键的距离

3. 测试运行

在java源文件上方的地址栏中输入CMD 打开DOS命令窗口

1.输入 javac + java文件名 编译 ,将java文件编译为class文件(c 表示单词 Complier 即编译的意思)

2.输入 java + class文件名 执行class文件

4.关键字

  • 1.什么是关键字?

    • 被Java官方赋予了特殊含义的单词 全部小写

  • 2.注意事项:

    • 关键字众多,不需要记忆,注意后续取名字避免和关键字冲突即可

第一个Java程序的扩展

1.详解代码

/**
*/
​
//公有的类叫做Hello 
public class Hello{
​
    //这种固定写法的方法叫做主方法
    public static void main(String[] args){
​
        //打印语句
        System.out.println("HelloWorld...1");
        System.out.println("HelloWorld...2");
        System.out.println("HelloWorld...3");
    }
}
​
/*
    public-公有的  class-类     Hello-类名
    static-静态的  void-无返回值的  main-方法名
    String-字符串类型 ps:"用良心做教育"
    String[]-字符串类型的数组 ps:["小红","小绿","小黄","明日花绮罗"]
    args-数组名
*/

2.代码细节

  1. public修饰的类名必须和文件名一致

  2. Java是一门大小写敏感的语言

  3. 括号都是成双成对的

  4. 方法里的代码都是从上往下执行-顺序执行

  5. 方法中的代码又叫做执行语句,执行语句用分号结束

2、Java代码规范

1.书写格式

经验:灵活使用tab(缩进键)

优先级别:类 > 方法 > 执行语句

2.代码注释

注释描述
//注释内容单行注释
/*注释内容*/多行注释
/**注释内容*/文档注释

编译的过程:Hello.java -> Hello.class

反编译的过程:Hello.class -> Hello.java

注意:

  1. 使用Xjad工具进行反编译

  2. 注释不会随着编译,而编译到class文件中

3、Path的作用

%JAVA_HOME%/bin --> javac.exe 和 java.exe

理解:在path中配置了某个目录,代表在其他任何目录里都可以打开配置的目录中的文件

见 path的作用.png

4、Java的扩平台特性

见 Java跨平台特性.png

三.Java 基本数据类型与算数运算符

1. 基本数据类型的深入

取值范围顺序

Java 中基本数据类型的取值范围从小到大依次为:byte < short < int < long < float < double

其中,

byte 占 1 个字节(8 位),取值范围是 -128 到 127;

short 占 2 个字节(16 位);

int 占 4 个字节(32 位);

long 占 8 个字节(64 位);

float 占 4 个字节(32 位),用于表示单精度浮点数;

double 占 8 个字节(64 位),用于表示双精度浮点数。

特殊情况

  • char 类型char 类型用于表示单个字符,它可以转换为 int 类型,从而获取字符对应的 ASCII 值。例如:

char c1 = 'A'; 
char c2 = 'a';
int i1 = c1;
int i2 = c2;
System.out.println(i1); // 输出 65
System.out.println(i2); // 输出 97
  • boolean 类型boolean 类型只有两个值:truefalse,它不能与其他基本数据类型进行转换。例如:

boolean bool = true;
// 以下代码会编译错误
// System.out.println((int)bool); 

字面量赋值

  • byteshort 类型:如果赋值的字面量在其取值范围内,可以直接赋值。例如:byte b1 = 1;。如果字面量超出了其取值范围,需要进行强制类型转换。例如:byte b2 = (byte)128;,此时会发生溢出,b2 的值为 -128。这是因为 128 的二进制表示(32 位)为 0000 0000 0000 0000 0000 0000 1000 0000,强制转换为 byte 类型(8 位)后变为 1000 0000,在补码表示中,这表示 -128。

  • long 类型:如果赋值的字面量超出了 int 类型的取值范围,需要在字面量后面加上 Ll。例如:long l2 = 12345678901L;

  • float 类型int 类型可以自动转换为 float 类型。例如:float f1 = 1;double 类型转换为 float 类型需要进行强制类型转换或使用 f 后缀。例如:float f2 = (float)1.0;float f2 = 1.0f;

2. 基本数据类型的转型(注意特殊点)

自动转型

取值范围小的类型会自动转换为取值范围大的类型,这是由 Java 编译器自动完成的,无需手动干预。例如:

byte b = 100;
short s = b;
int i = s;
long l = i;
float f = l;
double d = f;
System.out.println(d); // 输出 100.0

强制转型

取值范围大的类型转换为取值范围小的类型时,需要使用强制类型转换符 (type)。例如:

double d = 123.123;
float f = (float)d;
long l = (long)f;
int i = (int)l;
short s = (short)i;
byte b = (byte)s;
System.out.println(b); // 输出 123

特殊点

  • 类型提升:在进行运算时,如果操作数的类型不同,会自动将取值范围小的类型提升为取值范围大的类型。例如,byteshort 类型进行运算时,会自动转换为 int 类型,结果也为 int 类型。如果需要将结果赋值给 byteshort 类型,需要进行强制类型转换。例如:

byte b1 = 10;
byte b2 = 20;
byte result = (byte)(b1 + b2);
System.out.println(result);
  • 溢出问题:强制类型转换可能会导致数据溢出。例如,将一个超出目标类型取值范围的数进行强制转换,会得到一个错误的结果。如上面的 byte b2 = (byte)128;//-128 示例。

3. 算数运算符的使用

基本算数运算符

Java 中的基本算数运算符包括 +(加法)、-(减法)、*(乘法)、/(除法)、%(取模,即取余数)。例如:

int a = 10;
int b = 3;
int result = a + b;
System.out.println(result); // 输出 13
System.out.println(a + b); // 输出 13
System.out.println(10 + 3); // 输出 13
System.out.println(10 - 3); // 输出 7
System.out.println(10 * 3); // 输出 30
System.out.println(10 / 3); // 输出 3,整数除法会舍去小数部分
System.out.println(10 % 3); // 输出 1

自增自减运算符

  • ++:自增 1,分为前缀自增(先自增,后使用)和后缀自增(先使用,后自增)。例如:

  • 底层实现需要考虑byte或short:++a  等价于  (type)(a+1)

int a = 10;
System.out.println(++a); // 先将 a 自增为 11,然后输出 11
System.out.println(a); // 输出 11
​
int b = 10;
System.out.println(b++); // 先输出 b 的值 10,然后 b 自增为 11
System.out.println(b); // 输出 11
  • --:自减 1,分为前缀自减(先自减,后使用)和后缀自减(先使用,后自减)。例如:

int c = 10;
System.out.println(--c); // 先将 c 自减为 9,然后输出 9
System.out.println(c); // 输出 9
​
int d = 10;
System.out.println(d--); // 先输出 d 的值 10,然后 d 自减为 9
System.out.println(d); // 输出 9

4. 算数运算符的深入(注意特殊点和面试题)

特殊点

  • byteshort 运算byteshort 类型进行运算时,会自动转换为 int 类型,结果也为 int 类型。如果需要将结果赋值给 byteshort 类型,需要进行强制类型转换。例如:

byte b1 = 10;
byte b2 = 20;
byte result = (byte)(b1 + b2);
System.out.println(result);
  • 浮点数运算floatdouble 类型进行运算时可能会出现精度丢失的问题。这是因为浮点数在计算机中是以二进制形式存储的,有些十进制小数无法精确表示为二进制小数。例如:

double d1 = 0.5d;
double d2 = 0.4d;
System.out.println(d1 - d2); // 输出 0.0999999998,而不是 0.1
  • 字符参与运算:字符在参与运算时,会使用其对应的 ASCII 值。例如:

char c = 'a'; // 'a' 的 ASCII 值为 97
System.out.println(c + 1); // 输出 98

面试题

  • 复杂表达式计算

int a = 8;
int b = (a++) + (++a) + (a * 10);
// 首先,a++ 先使用 a 的值 8,然后 a 变为 9
// 接着,++a 先将 a 自增为 10,然后使用 a 的值 10
// 最后,a * 10 即 10 * 10 = 100
// 所以 b = 8 + 10 + 100 = 118
System.out.println(b); // 输出 118
  • 自增赋值问题

int i = 0;   
i = ++i; 
// ++i 先将 i 自增为 1,然后将 1 赋值给 i
System.out.println(i); // 输出 1
​
int j = 0;   
j = j++; 
// 首先,j++ 先使用 j 的值 0,将 0 保存到一个临时变量中
// 然后,j 自增为 1
// 最后,将临时变量中的 0 赋值给 j
System.out.println(j); // 输出 0

四.Java 基础语法与运算符详解

1.赋值运算符

符号

  • 注意:=为赋值号,将赋值号右侧的数据赋值给左侧的变量

  • =, +=, -=, *=, /=, %=

复合赋值运算符会自动进行类型转换:

short s = 1; // 等价于 s = (short)(1);
s += 1; // 等价于 s = (short)(s + 1);

赋值规则:
                     s   += 1                 s  = (T)((s)   +   (1))
            复合赋值 E1 op= E2等价于简单赋值 E1 = (T)((E1) op     (E2)),
            其中T是E1的类型。
 

2.字符串拼接符

规则

  • + 两侧均为数值时,执行算术运算。

  • 任意一侧为字符串时,执行字符串拼接。

示例

System.out.println(1 + 2 + "abc" + "def" + 1 + 2);
// 运算顺序:3 → "3abc" → "3abcdef" → "3abcdef1" → "3abcdef12"

3.Scanner 输入类

使用步骤

  1. 导包import java.util.Scanner;

  2. 实例化Scanner scan = new Scanner(System.in);

  3. 读取输入注意:没有char类型的数据输入

    int i = scan.nextInt();      // 读取整数
    double d = scan.nextDouble();// 读取浮点数
    String str = scan.next();    // 读取字符串(空格分隔)

4.关系运算符

符号

  • ==, !=, >, >=, <, <=

注意事项

  • == 比较值是否相等,= 是赋值。

  • 结果始终为 boolean 类型。

经典面试题

int x = 10, y = 10;
boolean flag = (x = y); // 编译错误:int 不能赋给 boolean
import java.util.Scanner;
public class Test04{
	/**
		知识点:关系运算符
		符号:==、!=、>、>=、<、<=
		
		注意:
			1.=是赋值运算符,将右侧的值赋值给左侧的变量
			2.==是关系运算符,判断两个值是否相等
			3.!=是关系运算符,判断两个值是否不相等
			4.关系运算符的结果必须是boolean类型
			

	*/
	public static void main(String[] args){
				boolean bool = 10 == 20;
		System.out.println(bool);//false
		System.out.println(10 != 20);//true
		System.out.println(10 >  20);//false
		System.out.println(10 >= 20);//false
		System.out.println(10 <  20);//true
		System.out.println(10 <= 20);//true
		
		需求:在控制台输入两个int类型的数字,比较大小
			Scanner scan = new Scanner(System.in);
		
			System.out.println("请输入第一个数字:");
			int a = scan.nextInt();
			System.out.println("请输入第二个数字:");
			int b = scan.nextInt();
			
			boolean bool = a > b;
			System.out.println("第一个数字是否比第二个数字大:" + bool);
			
		经典面试题一:输出结果为?
			int x = 10;
			int y = 10;
			boolean flag = (x == y);
			System.out.println(flag);//true
			flag = (x = y);//会报错,原因boolean类型不能与其他类型兼容
			System.out.println(flag);
			
		经典面试题二:输出结果为?
			boolean b1 = true;
			boolean b2 = false;
			boolean b3 = (b1 == b2);
			System.out.println(b3);//false -- 比较是否相同
			boolean b4 = (b1 = b2);
			System.out.println(b4);//false -- 连续赋值
		
		
		
		
	}
}

5.逻辑运算符

符号与特性

运算符名称特性
&逻辑与两侧均执行
&&短路与左侧为 false 则短路
|逻辑或逻辑或两侧均执行
||短路或左侧为true则短路
^异或两侧不同为 true
!取反

应用示例

boolean inRange = num > 50 && num < 100; // 判断数字是否在区间内
System.out.println(false && 10/0 > 5);   // 不报错(短路特性)
import java.util.Scanner;
public class Test05{
	/**
		知识点:逻辑运算符
		符号:
			&与		&&短路与
			|或		||短路或
			^异或
			!非
			
		注意:
			1.逻辑运算符运行结果都是boolean类型
			2.&、&&、|、||、^ 两侧都是boolean类型数据
			
		
	*/
	public static void main(String[] args){
		
		//&与:前后两侧都接boolean值,两侧同时成立(true),结果才为true
		System.out.println(true & true);//true
		System.out.println(false & true);//false
		System.out.println(true & false);//false
		System.out.println(false & false);//false
		
		//&&短路与:前后两侧都接boolean值,两侧同时成立(true),结果才为true
		System.out.println(true && true);//true
		System.out.println(false && true);//false
		System.out.println(true && false);//false
		System.out.println(false && false);//false
		
		//&与:判断前者为false后,还会判断后者
		//&&短路与:判断前者为false后,不会判断后者,效率更高
		//ArithmeticException -- 算数异常
		System.out.println(false && 10/0>5);
		
		//|或:前后两侧都接boolean值,两侧有一侧成立(true),结果就为true
		System.out.println(true | true);//true
		System.out.println(false | true);//true 
		System.out.println(true | false);//true
		System.out.println(false | false);//false
		
		//||短路或:前后两侧都接boolean值,两侧有一侧成立(true),结果就为true
		System.out.println(true || true);//true
		System.out.println(false || true);//true 
		System.out.println(true || false);//true
		System.out.println(false || false);//false
		
		//|或:判断前者为true后,还会判断后者
		//||短路或:判断前者为true后,不会判断后者,效率更高
		System.out.println(true || 10/0>5);
		
		//^异或:前后两侧都接boolean值,两侧不同为true,相同为false
		System.out.println(true ^ true);//false
		System.out.println(false ^ true);//true
		System.out.println(true ^ false);//true
		System.out.println(false ^ false);//false
		
		//!非:置反,true变为false,false变为true
		boolean bool1 = true;
		System.out.println(!bool1);//false
		boolean bool2 = false;
		System.out.println(!bool2);//true
		
		需求:在控制台输入一个int类型的数字,判断是否在50~100的区间内
		Scanner scan = new Scanner(System.in);
		System.out.println("请输入int类型的数字:");
		int num = scan.nextInt();
		
		boolean bool = num>50 && num<100;
		System.out.println("该数字是否在50~100的区间内:" + bool);
		
	}
}

6.三元运算符

语法

变量 = (条件) ? 值1 : 值2;

返回值类型规则

  1. 类型相同:直接返回该类型。

  2. 基本类型兼容:自动类型提升。

  3. 混合类型(基本与包装类):自动拆箱/装箱。

  4. 常量与变量:按兼容性决定类型。

    常量的值是否在变量所属类型的取值范围里

    在 - 按照变量的类型返回数据

    不在 - 按照常量的类型返回数据  

import java.util.Scanner;
public class Test06{
	/**
		知识点:表达式
			5 + 6 -- 算数表达式
			5 > 6 -- 关系表达式
	
		知识点:三目运算符/三元运算符
		
		语法规则:变量 = (表达式)?值1:值2;
		理解:表达式的结果必须是boolean
			  true - 将值1赋值给变量
			  false- 将值2赋值给变量
		做实验:

	*/
	public static void main(String[] args){

			int num = (false)?10:20;
			System.out.println(num);
			
		需求1:在控制台输入2个int类型的数字,比较大小,输出最大值
			Scanner scan = new Scanner(System.in);
			System.out.println("请输入第一个数字:");
			int a = scan.nextInt();
			System.out.println("请输入第二个数字:");
			int b = scan.nextInt();
			
			int max = (a>b)?a:b;
			System.out.println("最大值为:" + max);
			
		需求2:在控制台输入2个int类型的数字,比较大小,输出最小值
			Scanner scan = new Scanner(System.in);
			System.out.println("请输入第一个数字:");
			int a = scan.nextInt();
			System.out.println("请输入第二个数字:");
			int b = scan.nextInt();
			
			int min = (a<b)?a:b;
			System.out.println("最小值为:" + min);
			
		需求3:在控制台输入3个int类型的数字,比较大小,输出最大值
			Scanner scan = new Scanner(System.in);
			System.out.println("请输入第一个数字:");
			int a = scan.nextInt();
			System.out.println("请输入第二个数字:");
			int b = scan.nextInt();
			System.out.println("请输入第三个数字:");
			int c = scan.nextInt();
			
			int max = (a>b)?a:b;
			max = (max>c)?max:c;
			System.out.println("最大值为:" + max);
			
		需求4:在控制台输入3个int类型的数字,比较大小,由小到大输出(10<20<30)
			Scanner scan = new Scanner(System.in);
			System.out.println("请输入第一个数字:");
			int a = scan.nextInt();
			System.out.println("请输入第二个数字:");
			int b = scan.nextInt();
			System.out.println("请输入第三个数字:");
			int c = scan.nextInt();
			
			//最大值
			int max = (a>b)?a:b;
			max = (max>c)?max:c;
			
			//最小值
			int min = (a<b)?a:b;
			min = (min<c)?min:c;
			
			//中间值
			int mid = a+b+c-max-min;
			
			System.out.println(min + "<" + mid + "<" + max);
			
			
		扩展面试题1:
			int a = 5;
			System.out.println((a<5)?10.9:9);//9.0
			
		扩展面试题2:
			char x = 'x';//码值 - 120
			int i = 10;
			System.out.println(false?i:x);//120
			
		扩展面试题3:
			char x = 'x';//码值 - 120
			System.out.println(false?100:x);//x
			System.out.println(false?100000:x);//120
			
		扩展 -- 常量的概念:程序执行过程中不可发生改变的量
		注意:数字字面量是常量之一
			
		返回值规则:
			值1和值2都是常量时,按照取值范围大的类型返回数据
			值1和值2都是变量时,按照取值范围大的类型返回数据
			值1和值2一个是常量一个是变量,判断常量的值是否在变量所属类型的取值范围里
				在 - 按照变量的类型返回数据
				不在 - 按照常量的类型返回数据
		
	}
}

扩展面试题 ::注意这里的char类型的常量为规则变量跟常量,暂时把'X'看做是个变量

System.out.println(false ? 100 : 'x');   // 输出 'x'(char 类型)
System.out.println(false ? 100000 : 'x');// 输出 120(char 提升为 int)

7.位运算符

符号与功能

运算符名称功能
&位与两位为 1 则结果为 1
|位或任意一位为 1 则结果为 1
^异或两位不同为 1
<<左移低位补 0,相当于乘以 2
>>右移高位补符号位,相当于除以 2
>>>无符号右移高位补 0

示例

int a = 19; // 0001,0011
int b = 25; // 0001,1001
System.out.println(a & b);  // 17 (0001,0001)
System.out.println(a << 3); // 8192 (左移 3 位)
System.out.println(-1024 >> 3);  // -128
System.out.println(-1024 >>> 3); // 536870784
import java.util.Scanner;
public class Test07{
	/**
		知识点:位运算符
		理解:将十进制的数据转换为二进制做运算
		符号:&、|、^、<<、>>、>>>
		
		
	*/
	public static void main(String[] args){

		//&与:同位比较,两位为1,结果才为1
		byte a = 19;//0001,0011
		byte b = 25;//0001,1001
					//0001,0001
		
		//a - byte:0001,0011
		//	 (int):0000,0000,0000,0000,0000,0000,0001,0011
		//b - byte:0001,1001
		//	 (int):0000,0000,0000,0000,0000,0000,0001,1001
		//    结果:0000,0000,0000,0000,0000,0000,0001,0001
		//  (byte):0001,0001
		byte result = (byte)(a & b);
		
		System.out.println(result);//17 - 0001,0001
		
		//|或:同位比较,两者有1,结果就为1
		int a = 19;//0000,0000,0000,0000,0000,0000,0001,0011
		int b = 25;//0000,0000,0000,0000,0000,0000,0001,1001
				   //0000,0000,0000,0000,0000,0000,0001,1011
		System.out.println(a | b);//27
		
		//^异或:同位比较,两者不同为1,相同为0
		int a = 19;//0000,0000,0000,0000,0000,0000,0001,0011
		int b = 25;//0000,0000,0000,0000,0000,0000,0001,1001
				   //0000,0000,0000,0000,0000,0000,0000,1010
		System.out.println(a ^ b);//10
		
		注意:
			&、|、^:前后两侧为数值,该符号为位运算符
			&、|、^:前后两侧为boolean,该符号为逻辑运算符
			
		//<<左移:整体向左移动n位,就用n个0补位,补到最低位
		//经验:向左移动1位,相当于乘以2
		int a = 1024;//0000,0000,0000,0000,0000,0100,0000,0000
					 //0000,0000,0000,0000,0010,0000,0000,0000
		System.out.println(a << 3);//8192
			
			
		//>>右移:整体向右移动n位,就用n个最高位补位(符号位),补到最高位
		//注意:正数右移用0补位,负数右移用1补位
		//经验:向右移动1位,相当于除以2
		int a = 1024;//0000,0000,0000,0000,0000,0100,0000,0000
					 //0000,0000,0000,0000,0000,0000,1000,0000
		System.out.println(a >> 3);//128
		
		int b = -1024;//1111,1111,1111,1111,1111,1100,0000,0000
					  //1111,1111,1111,1111,1111,1111,1000,0000
		
		System.out.println(b >> 3);//-128
		
		//>>>无符号位右移:整体向右移动n位,就用n个0补位,补到最高位
		//注意:无符号位右移和右移处理正数都是一样的,都用0补位
		int a = 1024;//0000,0000,0000,0000,0000,0100,0000,0000
					 //0000,0000,0000,0000,0000,0000,1000,0000
		System.out.println(a >>> 3);//128
		
		int b = -1024;//1111,1111,1111,1111,1111,1100,0000,0000
				     //0001,1111,1111,1111,1111,1111,1000,0000
		
		System.out.println(b >>> 3);//536870784
	}
}

8.扩展知识点

1. 三元运算符的特殊场景

  • null 处理:若一个表达式为 null,返回值类型由另一个表达式决定。

    Object result = (true) ? "Hello" : null; // 类型为 String
  • 自动拆箱陷阱:包装类为 null 时可能抛出 NullPointerException

    Integer b = null;
    int result = (false) ? 10 : b; // 运行时异常

2. 位运算符应用

  • 交换两个数(无需临时变量):

    a = a ^ b;
    b = a ^ b;
    a = a ^ b;
  • 快速计算:左移/右移实现乘除 2 的幂次。

3. 常量与变量混合运算

  • 若常量值在变量类型范围内,按变量类型返回;否则按常量类型返回。

示例

int a = 5;
System.out.println((a < 5) ? 10.9 : 9); // 输出 9.0(int 提升为 double)

总结: 运算符的优先级和类型转换规则是 Java 基础中的核心内容,理解这些规则可避免常见的编译错误和逻辑问题。建议通过实际编码验证不同场景下的行为,加深记忆。

五. 流程控制

Java 基础知识点总结

1. 转义字符

1.1 概念

在 Java 中,转义字符用于表示一些特殊的字符,例如双引号、单引号、反斜杠等。通过转义字符,可以在字符串中使用这些特殊字符而不产生语法错误。

1.2 常见转义字符及示例

转义字符含义示例代码输出结果
\"表示一个双引号字符System.out.println("老师说:\"好好学习\"");老师说:"好好学习"
\'表示一个单引号字符System.out.println("老师说:\'好好学习\'");老师说:' 好好学习'
\\表示一个反斜杠字符System.out.println("老师说:\\好好学习\\");老师说:\ 好好学习 \
\n表示换行System.out.print("好好学习\n");好好学习(换行)
\t表示水平制表符System.out.println("3*3=9\t3*4=12\t3*5=15");33=9 34=12 3*5=15

1.3 打印方法区别

println():打印内容后换行。

print():只打印内容,不换行。

示例代码:

java

System.out.print("好好学习\n");
System.out.print("天天向上");

输出结果:

好好学习 
天天向上

2. 常量

2.1 数字字面量

  • 整数默认类型为 int

  • 小数默认类型为 double

2.2 字面值常量

  • 双引号括起来的内容

2.3 final 修饰的常量

使用 final 关键字修饰的变量为常量,一旦赋值后不能再修改。

示例代码:

final int num = 100;
System.out.println(num++);//报错 无法为 final 变量 num 分配值

3. Java 执行流程

3.1 顺序结构

程序按照代码的书写顺序依次执行。

3.2 选择结构

3.2.1 if 语句
  • 语法结构:

if(条件表达式){
    // 语句块
}
  • 执行流程:条件表达式的结果为 boolean 类型,如果为 true,则执行语句块;如果为 false,则跳过 if 语句,继续执行后面的代码。

示例代码:

Scanner scan = new Scanner(System.in);
System.out.println("请输入成绩:");
double score = scan.nextDouble();
if(score > 98){
    System.out.println("恭喜你,一个奖励大娃娃");
}

3.3 循环结构

包括 for 循环、while 循环、do-while 循环。

3.4 跳转语句

包括 breakreturncontinuelable

4. 命名规范(Test04.java)

4.1 大驼峰命名法

用于类名,首字母大写,后续每个单词首字母也大写。例如:HelloWorld

4.2 小驼峰命名法(推荐)

用于变量名和方法名,第一个单词首字母小写,后续每个单词首字母大写。例如:javaScore

5. if...else... 语句

5.1 语法结构

if(条件表达式){
    // 语句块 1
} else {
    // 语句块 2
}

5.2 执行流程

条件表达式的结果必须为 boolean 类型,如果为 true,则执行语句块 1;如果为 false,则执行语句块 2。

示例代码:

Scanner scan = new Scanner(System.in);
System.out.println("请输入成绩:");
double score = scan.nextDouble();
if(score > 98){
    System.out.println("恭喜你,奖励一个大娃娃");
} else {
    System.out.println("很遗憾,继续努力");
}

6. 多重 if 语句

6.1 语法结构

if(条件表达式 1){
    // 语句块 1
} else if(条件表达式 2){
    // 语句块 2
} else if(条件表达式 n){
    // 语句块 n
} else {
    // 语句块 else
}

6.2 执行流程

依次判断条件表达式,如果某个条件表达式为 true,则执行对应的语句块,然后跳出多重 if 语句;如果所有条件表达式都为 false,则执行 else 语句块(如果有)。

示例代码:

Scanner scan = new Scanner(System.in);
System.out.println("请输入成绩:");
double score = scan.nextDouble();
if(score >= 90 && score <= 100){
    System.out.println("A");
} else if(score >= 80 && score < 90){
    System.out.println("B");
} else if(score >= 70 && score < 80){
    System.out.println("C");
} else if(score >= 60 && score < 70){
    System.out.println("D");
} else if(score >= 0 && score < 60){
    System.out.println("E");
} else {
    System.out.println("成绩错误");
}

7. 嵌套 if 语句

在一个 if 语句中可以嵌套另一个 if 语句,用于处理更复杂的条件判断。

小结:if可以无限层嵌套 

经验:if嵌套最好不要超过3层(考虑到可读性)

示例代码:

Scanner scan = new Scanner(System.in);
System.out.println("请输入考试成绩:");
double score = scan.nextDouble();
if(score >= 0 && score < 16){
    System.out.println("可以报名");
    String sex = scan.next();
    if(sex.equals("男")){
        System.out.println("欢迎来到男子组");
    } else if(sex.equals("女")){
        System.out.println("欢迎来到女子组");
    } else {
        System.out.println("报名错误");
    }
} else if(score >= 16){
    System.out.println("很遗憾,你不能参加...");
} else {
    System.out.println("成绩错误");
}
 

8. switch 语句

8.1 语法结构

switch(表达式){
    case 值 1:
        // 语句块 1
        break;
    case 值 2:
        // 语句块 2
        break;
    case 值 n:
        // 语句块 n
        break;
    default:
        // 语句块 default
        break;
}

8.2 执行流程

表达式的值与各个 case 后面的值进行比较,如果相等,则执行对应的语句块,直到遇到 break 语句跳出 switch 语句;如果所有 case 值都不匹配,则执行 default 语句块(如果有)。

8.3 注意事项

  • case 后面的值不能重复。

  • default 语句可以省略。

  • break 语句可以省略,如果省略,会继续执行下一个 case 语句块,直到遇到 breakswitch 语句结束。

  • 表达式的值可以是 byteshortintcharString(JDK1.7 及以上)、枚举(JDK1.5 及以上)。

  • switch底层逻辑是什么?

    • 将表达式的值转化为int类型

    输入类型转化类型方式
    byteint自动转型
    shortint自动转型
    intint直接使用
    charint获取码值
    Stringint获取hash值
    枚举int获取枚举对象的编号
    • 获取hash值:

      • (String的hash值就是获取的字符的码值 + 散列算法,算出来的一个int值)

示例代码

Scanner scan = new Scanner(System.in);
System.out.println("请输入抽奖序号:");
String str = scan.next();
switch(str){
    case "一等奖":
        System.out.println("获得一台华为电脑");
        break;
    case "二等奖":
        System.out.println("获得一部苹果手机");
        break;
    case "三等奖":
        System.out.println("获得一个移动硬盘");
        break;
    default:
        System.out.println("老师会详细讲解抽奖规则");
        break;
}

案例

  • 需求:输入年和月,输出当月的天数

import java.util.Scanner;
public class Test09{
	public static void main(String[] args){
					Scanner scan = new Scanner(System.in);
			System.out.println("请输入年:");
			int year = scan.nextInt();
			System.out.println("请输入月:");
			int month = scan.nextInt();
		
			int day = 0;
			switch(month){
				case 1:case 3:case 5:case 7:case 8:case 10:case 12:
					day = 31;
				break;
				case 4:case 6:case 9:case 11:
					day = 30;
				break;
				case 2:
					if(year%4==0 && year%100!=0 || year%400==0){
						day = 29;
					}else{
						day = 28;
					}
				break;
			}
			System.out.println(year + "年" + month + "月当月的天数为:" + day + "天");
	}
}

switch判断区间

int num = 3;
switch (num) {
    case 1:
    case 2:
    case 3:
        System.out.println("1-3");
        break;
    case 4:
    case 5:
        System.out.println("4-5");
        break;
    default:
        System.out.println("其他");
}

8.4 if 与 switch 的比较

  • 表达式类型

    • if 的条件表达式为 boolean 类型;

    • switch 的表达式可以是 byteshortintcharString、枚举。

  • 应用场景

    • if 适用于复杂的条件判断;

    • switch 适用于判断值的情况。

六.循环语句

1. for 循环

1.1 语法结构

for(表达式 1; 表达式 2; 表达式 3){
    // 语句块
}

理解: 

表达式1 -- 初始化变量 ​

表达式2 -- 判断条件 ​

表达式3 -- 更新变量

1.2 执行流程

  1. 执行表达式 1,进行初始化操作。

  2. 执行表达式 2,进行条件判断,结果为boolean类型。

    • 如果为 true,则执行语句块,然后执行表达式 3,再回到步骤 2 继续判断。

    • 如果为 false,则跳出循环。

示例代码:

for(int i = 1; i <= 10; i++){
    System.out.println(i);
}

 

1.3 常见应用场景

  • 打印一定范围内的数字。

  • 循环输入数据并进行求和、求平均值、找最大值等操作。

示例代码(求 5 个整数的和):

Scanner scan = new Scanner(System.in);
int sum = 0;
for(int i = 1; i <= 5; i++){
    System.out.println("请输入第" + i + "个数字:");
    int num = scan.nextInt();
    sum += num;
}
System.out.println("总和为:" + sum);
知识点
  • 用于已知循环次数的情况。

  • 语法结构:for(初始化语句; 判断条件; 迭代语句){ 循环体 }

示例代码
// 打印矩形图案
for(int i = 0;i<3;i++){
    for(int j = 0;j<4;j++){
        System.out.print("*");
    }
    System.out.println();
}
代码解释
  • 外层循环控制行数,内层循环控制每行的列数。通过嵌套循环可以打印出各种图案。

2. while 循环

知识点
  • 用于循环次数不确定,但有明确判断条件的情况。

  • 语法结构:while(判断条件){ 循环体 }

示例代码
int i = 0;
while(i<5){
    System.out.println("循环执行中");
    i++;
}
代码解释
  • 先判断条件,条件为true则执行循环体,执行完后再次判断条件,直到条件为false

3. do - while 循环

知识点
  • 先执行一次循环体,再判断条件。保证循环体至少执行一次。

  • 语法结构:do{ 循环体 }while(判断条件);

示例代码
Scanner scan = new Scanner(System.in);
String str;
do{
    System.out.println("请输入内容");
    str = scan.next();
}while(str.equals("继续"));
代码解释
  • 无论条件是否成立,循环体都会先执行一次,然后再根据条件决定是否继续循环。

4. 循环控制语句

4.1 break

知识点
  • 循环中使用,用于终止当前循环。

示例代码
Scanner scan = new Scanner(System.in);
boolean flag = true;
double sum = 0;
for(int i = 1;i<=5;i++){
    System.out.println("请输入第" + i + "个成绩");
    double score = scan.nextDouble();
    if(score < 0){
        flag = false;
        break;
    }
    sum += score;
}
代码解释
  • 当输入的成绩为负数时,使用break语句终止循环。

4.2 continue

Scanner scan = new Scanner(System.in);
int count = 0;
for(int i = 1;i<=5;i++){
    System.out.println("请输入第" + i + "个学生的成绩");
    double score = scan.nextDouble();
    if(score < 80){
        continue;
    }
    count++;
}
知识点
  • 在循环中使用,用于跳过本次循环,直接进入下一次循环。

代码解释
  • 当输入的成绩小于 80 分时,使用continue语句跳过本次循环,不执行count++

4.3 return

知识点
  • 在方法中使用,用于返回方法的结果,并终止当前方法的执行。

示例代码
public static void main(String[] args) {
    System.out.println("111");
    System.out.println("222");
    if(true){
        return;
    }
    System.out.println("333");
}
代码解释
  • 当条件为true时,使用return语句终止方法的执行,后面的System.out.println("333");不会执行。

4.4 label

知识点
  • 用于标记循环,可配合breakcontinue语句跳出指定的循环。

示例代码
a: for(int i = 1;i<=5;i++){
    for(int j = 1;j<=3;j++){
        if(i == 3){
            break a;
        }
        System.out.println(i + " -- " + j);
    }
}
代码解释
  • i等于 3 时,使用break a;语句跳出标记为a的外层循环。

5. 静态方法

知识点
  • static关键字修饰的方法,可通过类名直接调用。

  • 语法结构:public static 返回值类型 方法名(参数列表){ 方法体 }

方法的调用

  •   在需要调用方法的位置直接书写方法名()即可调用。
示例代码
public static void printStar(){
    for(int i = 0;i<5;i++){
        for(int j = 0;j<=i;j++){
            System.out.print("*");
        }
        System.out.println();
    }
}
代码解释
  • printStar方法是一个静态方法,可通过Test10.printStar();调用。

6. 日期计算与日历打印

知识点
  • 涉及日期计算,判断闰年,计算指定年月的第一天是星期几,以及打印日历。

示例代码
Scanner scan = new Scanner(System.in);
System.out.println("请输入年份:");
int year = scan.nextInt();
System.out.println("请输入月份:");
int month = scan.nextInt();
// 计算指定年份前的总天数
int allDayOfYear = 0;
for(int i = 1900;i<year;i++){
    if(i%4==0 && i%100!=0 || i%400==0){
        allDayOfYear += 366;
    } else {
        allDayOfYear += 365;
    }
}
代码解释
  • 首先获取用户输入的年份和月份,然后计算从 1900 年到指定年份前一年的总天数,根据闰年规则判断每年的天数。

七.方法的重载递归

方法的重载

知识点
  • 条件

    • 同一类中,方法名相同,参数列表不同(类型或数量或顺序)。

    • 与返回值无关以及访问权限修饰符无关 。

  • 优点:根据实参类型自动匹配方法。

代码示例

public class Test03 {
    public static void main(String[] args) {
        System.out.println(getMax(10, 20, 30.3));
    }
​
    // 重载示例
    public static int getMax(int a, int b) { /*...*/ }
    public static int getMax(int a, int b, int c) { /*...*/ }
    public static double getMax(double a, double b) { /*...*/ }
    public static double getMax(double a, double b, double c) { /*...*/ }
}

4. 方法的递归(错误示例)

知识点
  • 递归错误:死循环导致栈溢出(StackOverflowError)。

  • 原因:每次递归调用都会在栈中开辟新空间,无限调用导致内存耗尽。

代码示例

public class Test04 {
    public static void main(String[] args) {
        method(); // 错误示例
    }
​
    public static void method() {
        method(); // 无限递归
    }
}

总结

  • 方法:注重参数传递、返回值、重载与递归的合理使用。

  • 数组:掌握静态/动态初始化、遍历方式及常见操作(如求最值)。

  • 递归:必须定义出口,避免栈溢出。

  • 代码规范:方法功能单一,变量命名清晰,逻辑分层明确。


5. 递归实现阶乘

知识点
  • 递归要点

    • 规律n! = (n-1)! * n

    • 出口1! = 1

代码示例

public class Test05 {
    public static void main(String[] args) {
        System.out.println(method(5)); // 输出120
    }
​
    public static int method(int n) {
        return (n == 1) ? 1 : method(n - 1) * n;
    }
}
 

6. 方法版本的万年历

知识点
  • 功能分解

    • 计算总天数、判断闰年、获取当月天数、打印日历。

  • 关键方法

    • getAllDay:计算从基准年(1900)到目标年的总天数。

    • getWeek:计算某月第一天的星期。

代码结构

//封装方法万历表
import java.util.Scanner;
public class Test06{
    public static void main(String[] args){
        Scanner scan = new Scanner(System.in);
        System.out.println("请输入年:");
        int year = scan.nextInt();
        System.out.println("请输入月:");
        int month = scan.nextInt();
        
        //获取星期
        int week = getWeek(year,month);
        
        //获取当月的天数
        int day = getDay(year,month);
        
        //打印日历
        printCalendar(year,month,day,week);
        
        
    }
    //打印日历
    public static void printCalendar(int year,int month,int day,int week){
        System.out.println(year + "年" + month + "月");
        System.out.println("一\t二\t三\t四\t五\t六\t日");
        
        int count = 0;
        
        for(int i = 1;i<week;i++){
            System.out.print("\t");
            count++;
        }
        
        for(int i = 1;i<=day;i++){
            System.out.print(i + "\t");
            count++;
            if(count % 7 == 0){
                System.out.println();//换行
            }
        }
    }
    //获取星期
    public static int getWeek(int year,int month){
        int week = getAllDay(year,month)%7;
        if(week == 0){
            week = 7;
        }
        return week;
    }   
    
    //获取总天数
    public static int getAllDay(int year,int month){
        int allDay = getAllDayOfMonth(year,month) + getAllDayOfYear(year)+1;
        return allDay;
    }
    
    //获取月的总天数
    public static int getAllDayOfMonth(int year,int endMonth){
        int AllDayOfMonth = 0;
        for(int i = 1;i < endMonth;i++){
            AllDayOfMonth += getDay(year,i);
        }
        return AllDayOfMonth;
    }
    
    //获取当月的天数
    public static int getDay(int year,int month){
        int day = 0;
        switch(month){
            case 1:case 3:case 5:case 7:case 8:case 10:case 12:
                day = 31;
            break;
            case 4:case 6:case 9:case 11:
                day = 30;
            break;
            case 2:
                if(isLeapYear(year)){
                    day = 29;
                }else{
                    day = 28;
                }
            break;
        }
        return day;
    }
​
    //获取年的总天数
    public static int getAllDayOfYear(int year){
        int allDayOfYear =0;
        for(int i = 1900;i < year; i++){
            if(isLeapYear(i)){
                allDayOfYear += 366;
            }else{
                allDayOfYear += 365;
            }
        }
        return allDayOfYear;
    }
    
    //判断是否是闰年
    public static boolean isLeapYear(int year){
        if(year % 4 == 0 && year % 100 !=0 || year % 400 == 0){
            return true;
        }else{
            return false;
        }
    }
}

八.数组

1.数组的概念:

                     一组`连续`的存储空间,存储多个`相同`数据类型的值,长度是`固定`的。

2. 数组的定义

先声明、再分配空间: 数据类型[] 数组名; 数组名 = new 数据类型[长度];

声明并分配空间: 数据类型[] 数组名 = new 数据类型[长度];

声明并赋值(繁): 数据类型[] 数组名 = new 数据类型[]{value1,value2,value3,...};

声明并赋值(简): 数据类型[] 数组名 = {value1,value2,value3,...};

3. 数组的使用

数组的元素:数组中的每个数据称之为数组中的元素

数组的访问:对数组中的元素赋值以及取值的操作 统称为数组的访问

下标、索引、角标、index : 下标自动生成 从0开始 往后依次+1

访问数组通过下标访问:

赋值 数组名[下标] = 值;

取值 System.out.println(数组名[下标]);

访问不存在的下标 将会导致数组下标越界异常 ArrayIndexOutOfBoundsException

一维数组

知识点
  • 静态初始化String[] names = {"A", "B", "C"};

  • 遍历方式

    • for循环(需下标时使用)。

    • foreach循环(无需下标时使用)。

代码示例

public class Test07 {
    public static void main(String[] args) {
        String[] names = {"麻生希", "椎名空", "王舟毅"};
        for (String name : names) {
            System.out.println(name);
        }
    }
}

4. 一维数组(动态初始化)

知识点
  • 动态初始化String[] names = new String[5];

  • 默认值

    • int:0,double:0.0,boolean:false,引用类型:null

代码示例

public class Test08 {
    public static void main(String[] args) {
        String[] names = new String[5];
        names[0] = "白鸽";
    }
}

//{白鸽,null,null,null,null}

5. 数组应用:最大值查找

知识点
  • 步骤

    • 动态初始化数组并录入数据。

    • 遍历比较求最大值。

代码示例

public class Test09 {
    public static void main(String[] args) {
        int[] arr = new int[5];
        // 录入数据...
        int max = arr[0];
        for (int num : arr) {
            if (num > max) max = num;
        }
        System.out.println("最大值:" + max);
    }
}

6.数组的扩容

数组的扩容:

实现步骤:

1.创建比原数组更长的新数组

2.将原数组中的元素依次复制到新数组中

3.将新数组的地址赋值给原数组

数组作为引用数据类型 其数组名中保存的是指向堆中的地址 所以 当我们把一个数组 赋值 给 另外一个数组 赋值的是地址

 

package com.atguigu.test4;


import java.util.Arrays;

/**
 *  数组的扩容:
 *  实现步骤:
 *      1.创建比原数组更长的新数组
 *      2.将原数组中的元素依次复制到新数组中
 *      3.将新数组的地址赋值给原数组
 */
public class TestArrayGrow {
    public static void main(String[] args) {
        int [] oldArr = {1,2,3,4,5};

        int [] newArr = new int[oldArr.length * 2];

        for(int i = 0;i < oldArr.length ;i++){
            newArr[i] = oldArr[i];
        }

        System.out.println(Arrays.toString(newArr));
        // 数组作为引用数据类型 其数组名中保存的是指向堆中的地址
        // 所以 当我们把一个数组 赋值 给 另外一个数组
        // 赋值的是地址

        System.out.println(oldArr);
        System.out.println(newArr);

        oldArr = newArr;
        System.out.println("==================地址赋值以后===================");

        System.out.println(oldArr);
        System.out.println(newArr);

        System.out.println(oldArr.length);

        System.out.println(Arrays.toString(oldArr));

        System.out.println("------------------------------------------------------------------");

        newArr[9] = 666;

        System.out.println(oldArr[9]); // 0? 666?
    }
}

 

 7.数组的复制

复制数组的三种方式:

循环将原数组中所有元素逐一赋值给新数组。

System.arraycopy(原数组,原数组起始,新数组,新数组起始,长度);

java.util.Arrays.copyOf(原数组, 新长度);//返回带有原值的新数组。

 

package com.atguigu.test4;

import java.sql.SQLOutput;
import java.util.Arrays;

/**
 * @author WHD
 * @description TODO
 * @date 2023/8/2 14:23
 *  复制数组的三种方式:
 *      循环将原数组中所有元素逐一赋值给新数组。
 *      System.arraycopy(原数组,原数组起始,新数组,新数组起始,长度);
 *      java.util.Arrays.copyOf(原数组, 新长度);//返回带有原值的新数组。
 */
public class TestArrayCopy {
    public static void main(String[] args) {
        int [] oldArr = {1,2,3,4,5};

        int [] newArr = new int[10];

        System.arraycopy(oldArr, 1, newArr, 2, 2);

        System.out.println(Arrays.toString(newArr));

        System.out.println("-------------------------------------------------");

        int [] nums = {11,22,33,44,55};

        // 第一个参数 原数组
        // 第二个参数 新长度 新长度可以小于等于或者大于原数组的长度
        int [] newNums = Arrays.copyOf(nums, 5);

        System.out.println(Arrays.toString(newNums));
    }
}

8.面试题

值传递和引用传递的区别?

Java官方明确指出 Java中只有值传递

基本数据类型属于'值传递',传递的就是值的副本,值的拷贝,在方法中对参数的修改不会影响原变量

引用数据类型属于'引用传递' 传递的是地址,也就是引用,在方法中对参数的修改会影响原变量

String类型是特殊的引用数据类型 作为参数不会影响原变量 因为String是不可变

 

9.可变长参数

可变长参数:可接收多个同类型实参,个数不限,使用方式与数组相同。

要求:

1.整个形参列表中只能有一个可变长参数

2.必须书写在形参列表的末尾

格式:数据类型...参数名

package com.atguigu.test6;

/**
 *  可变长参数:可接收多个同类型实参,个数不限,使用方式与数组相同。
 *  要求:
 *      1.整个形参列表中只能有一个可变长参数
 *      2.必须书写在形参列表的末尾
 *  格式:数据类型...参数名
 */
public class TestChangedParam {
    public static void m1(int ... args){
        System.out.println("m1方法开始执行");
        for(int i =0;i < args.length;i++){
            System.out.println(args[i]);
        }
        System.out.println("m1方法执行完毕");
    }
    public static void m2(int [] args){
        System.out.println("m2方法开始执行");
        for(int i =0;i < args.length;i++){
            System.out.println(args[i]);
        }
        System.out.println("m2方法执行完毕");
    }
    public static void main(String[] args) {
        m1(1,2,3,4,5,6);

        int [] nums = new int[4];
        m2(nums);

    }


}

10. Arrays工具类

java.util.Arrays 是JDK提供的一个用于操作数组的工具类

toString(数组名) : 将数组中的元素转换为字符串

copyOf(数组名,新长度) : 复制数组

sort(数组名) : 将数组按照升序排序 属于快速排序 实现原理为 递归

fill(数组名,填充元素) : 将数组按照指定元素进行填充

binarySearch(数组名,元素) : 使用二分查找法查找某个元素在数组中的下标

核心方法

方法功能说明注意事项
Arrays.sort(arr)数组排序(升序)修改原数组
Arrays.binarySearch(arr, key)二分查找元素下标必须已排序
Arrays.copyOf(arr, newLength)拷贝数组并指定新长度新长度可大于原数组长度
Arrays.fill(arr, value)用指定值填充数组可指定填充区间 (from, to)
Arrays.toString(arr)将数组转换为字符串输出格式:[e1, e2, e3]

代码示例

int[] arr = {67,81,37,72,41,18,88,22,44,66,11};
Arrays.sort(arr); // 排序后:[11, 18, 22, 37, 41, 44, 66, 67, 72, 81, 88]
int index = Arrays.binarySearch(arr, 37); // 返回3
int[] copy = Arrays.copyOf(arr, 15); // 新数组长度15,超出部分补默认值

package com.atguigu.test3;
​
import java.util.Arrays;
​
/**
 * @author WHD
 * @description TODO
 * @date 2023/8/4 14:05
 *  toString(数组名) : 将数组中的元素转换为字符串
 *  copyOf(数组名,新长度) : 复制数组
 *  sort(数组名) : 将数组按照升序排序
 *  fill(数组名,填充元素) : 将数组按照指定元素进行填充
 *  binarySearch(数组名,元素) : 使用二分查找法查找某个元素在数组中的下标
 */
public class TestArrays {
    public static void main(String[] args) {
        int [] nums = {56,12,22,41,85,99};
​
        Arrays.sort(nums);
​
        System.out.println(Arrays.toString(nums));
​
        int [] newArr = new int[nums.length];
​
        for(int i = 0,j = nums.length -1;i < nums.length;i++,j--){
            newArr[i] = nums[j];
        }
​
        System.out.println(Arrays.toString(newArr));
​
        System.out.println("--------------------------------------------");
​
        Arrays.fill(newArr, 666);
​
        System.out.println(Arrays.toString(newArr));
​
        System.out.println("--------------------------------------------");
​
        int index = Arrays.binarySearch(nums, 999);
​
        System.out.println("index = " + index);
​
    }
}

11. 数组插入元素

编写方法实现在数组中插入元素

扩展:可以使用System.arraycopy方法 实现插入效果

package com.atguigu.test3;
​
import java.util.Arrays;
​
/**
 * @author WHD
 * @description TODO
 * @date 2023/8/4 14:16
 *  编写方法实现在数组中插入元素
 *  扩展:可以使用System.arraycopy方法 实现插入效果
 */
public class TestArrayInsert {
    public static void main(String[] args) {
        int [] nums = {1,2,3,4,5};
        int[] newArray = insert(nums, -8, 666);
        System.out.println(Arrays.toString(newArray));
    }
    /**
     *
     * @param oldArray 操作的数据
     * @param index 插入元素的位置
     * @param num 插入的元素
     * @return 新的数组
     */
    public static int[] insert(int [] oldArray,int index,int num){
        // 下标不能小于0 或者 不能大于数组的长度
        if(index < 0 || index > oldArray.length){
            System.out.println("下标不合法");
            // 如果下标不合法 则将传入的数组 直接返回 表示没有做任何操作
            return oldArray;
        }
​
        // 代码执行到这里 表示下标没问题
        // 准备一个长度+1的数组 用于插入元素
        int [] newArray = new  int[oldArray.length + 1];
​
        // 遍历开始移动元素
        for(int i = 0;i < oldArray.length;i++){
            // 情况1 小于插入下标 则直接复制到新数组中
            if(i < index){
                newArray[i] = oldArray[i];
            }else{ // 情况2  大于或者等于插入下标 则移动到新数组的+1位置
                newArray[i + 1] = oldArray[i];
            }
        }
        // 空缺位插入指定的元素
        newArray[index] = num;
        return newArray; // 将新数组返回
    }
}

12.数组删除元素

编写方法实现删除数组中的元素

扩展:可以使用System.arraycopy方法 实现删除效果

package com.atguigu.test3;
​
import java.util.Arrays;
​
/**
 * @author WHD
 * @description TODO
 * @date 2023/8/4 14:31
 *  编写方法实现删除数组中的元素
 *  扩展:可以使用System.arraycopy方法 实现删除效果
 */
public class TestArrayDelete {
    public static int[] delete(int [] oldArray,int index){
        // 判断下标 如果小于0 或者 大于等于数组长度 表示不合法 因为删除 只能删除有效范围以内的
        if(index < 0 || index >= oldArray.length){
            System.out.println("下标不合法");
            return oldArray; // 直接将传入的原数组返回 表示没有做任何操作
        }
​
        // 准备一个长度-1的数组 用于删除之后复制元素
        int [] newArray = new int[oldArray.length - 1];
        // 循环遍历开始复制元素
        for(int i = 0;i < newArray.length;i++){
            if(i < index){ // 情况1 小于删除的下标 直接复制
                newArray[i] = oldArray[i];
            }else{ // 情况2 大于等于删除下标 则直接将原数组的+1位置 移动到新数组的后续位置 属于向左移动覆盖
                newArray[i] = oldArray[i +1];
            }
        }
        return newArray; // 将新数组返回
    }
​
    public static void main(String[] args) {
        int [] nums = {1,2,3,4,5};
        int[] delete = delete(nums, -5);
        System.out.println(Arrays.toString(delete));
    }
​
}

13.二维数组

二维数组:数组中的元素还是数组

package com.atguigu.test3;
​
/**
 * @author WHD
 * @description TODO
 * @date 2023/8/4 15:30
 *  二维数组:数组中的元素还是数组
 */
public class Test2DArray {
    public static void main(String[] args) {
        int [] arr1 = {1,2,3,4,5};
        int [] [] arr2 = { {1,2,4} ,  {55,88,66}  , {666} , {999,888,777}};
​
        System.out.println(arr2[0]);
        System.out.println(arr2[0][0]);
        System.out.println(arr2[0][1]);
        System.out.println(arr2[0][2]);
        System.out.println("----------------------------------");
        System.out.println(arr2[1][0]);
        System.out.println(arr2[1][1]);
        System.out.println(arr2[1][2]);
        System.out.println("----------------------------------");
        System.out.println(arr2[2][0]);
        System.out.println("----------------------------------");
        System.out.println(arr2[3][0]);
        System.out.println(arr2[3][1]);
        System.out.println(arr2[3][2]);
​
        System.out.println("----------------------------------");
​
        for(int i = 0;i < arr2.length;i++){
            System.out.println(arr2[i]);
            for(int j = 0;j < arr2[i].length;j++){
                System.out.print(arr2[i][j] + "\t");
            }
            System.out.println();
        }
​
​
    }
}

二维数组定义:和一维数组定义方式大致相同

二维开辟空间 高维度(第一个中括号)长度必须指定 低维度(第二个中括号)长度可以后续单独指定

package com.atguigu.test3;
​
/**
 * @author WHD
 * @description TODO
 * @date 2023/8/4 15:38
 *  二维数组定义:和一维数组定义方式大致相同
 *  二维开辟空间 高维度(第一个中括号)长度必须指定 低维度(第二个中括号)长度可以后续单独指定
 */
public class Test2DArrayDefine {
    public static void main(String[] args) {
        // 方式1
        int [][] arr1;
        arr1 = new int[3][4];
​
        // 方式2
        // 数组的默认值 二维数组每个元素为一维数组 属于引用数据类型 其默认值为null
        // 当我们创建一个长度为2的二维数组 表示在内存中 有两个一维数组 都指向为null
        int [][] arr2 = new int[2][];
​
        System.out.println(arr2[0]);
        System.out.println(arr2[1]);
​
​
        arr2[0] = new int[3];
        arr2[0][0] = 11;
        arr2[0][1] = 11;
        arr2[0][2] = 11;
​
        arr2[1] = new int[2];
        arr2[1][0] = 34;
        arr2[1][1] = 56;
​
​
        // 方式3
        int [][] arr3 = new int[][]{{1},{22,33,44},{55,55,666}};
​
        // 方式4
        int [][] arr4 = {{1},{22,33,44},{55,55,666}};
​
​
​
​
​
​
    }
}

二维数组实现:杨辉三角

package com.atguigu.test3;
​
/**
 * @author WHD
 * @description TODO
 * @date 2023/8/4 15:47
 *  杨辉三角
 *  1
 *  1   1
 *  1   2   1
 *  1   3   3   1
 *  1   4   6   4   1
 *  1   5   10  10  5   1
 */
public class TestYangHuiTriangle {
    public static void main(String[] args) {
        int [][] yh = new int[6][6];
        for(int i = 0;i < yh.length;i++){
            yh[i][0] = 1; // 每一行的第一列为1
            yh[i][i] = 1;
​
            if(i > 1){ // 表示从第3行开始 赋值有具体的计算
                for(int j = 1;j < i;j++){ // 因为每一行的第一列 和 最后一列都有值了 为0  所以 我们只需要赋值中间的元素
                    yh[i][j] = yh[i -1][j] + yh[i -1][j -1];
                }
            }
        }
        for(int i = 0;i < yh.length;i++){
            for(int j = 6;j >= i;j--){
                System.out.print(" ");
            }
            for(int j = 0;j <= i;j++){
                System.out.print(yh[i][j] + " ");
            }
            System.out.println();
        }
    }
}

九.面相对象

一、类与对象基础

1.1 类定义规范

//文档1基础类
public class Person {
    //成员变量(未封装)
    String name;
    char sex;
    int age;
    
    //成员方法
    public void eat(){...}
}

//文档4改进类
public class Person {
    //成员变量(封装改进)
    String name;
    char sex;
    int age;
    
    //使用this的成员方法
    public void eat(){
        System.out.println(this.name + " eating"); 
    }
}

核心知识点:​

  1. 类包含成员变量和成员方法
  2. 默认访问修饰符为包级私有(未显式声明时)
  3. this关键字用于明确访问当前对象成员
  4. 成员变量未初始化时系统默认赋值(String->null, int->0等)

1.2 对象创建与使用

//文档2测试类
Person p = new Person();
p.name = "张三";
p.eat();

//文档3多对象测试
Person p1 = new Person();
Person p2 = new Person();
p1.age = 23;
p2.age = 18;

对象特性:​

  • new关键字触发堆内存分配
  • 每个对象独立存储成员变量副本
  • 对象引用存储的是堆内存地址
  • 垃圾回收机制自动管理内存

二、封装与访问控制

2.1 private封装

//文档5私有化示例
public class A {
    private String str = "";
    private void method01(){...}
    
    public void method02(){
        method01(); //内部调用私有方法
    }
}

//文档6测试类
A a = new A();
a.method02(); //通过公有方法间接访问私有方法

封装原则:​

  1. 私有化字段(private修饰)
  2. 提供公有访问方法(getter/setter)
  3. 方法内部可添加业务逻辑控制

2.2 标准封装实现

//文档7完整封装类
public class User {
    private String username;
    private double money;
    
    //带验证的setter
    public void setMoney(double money) {
        System.out.println(LocalDateTime.now() + " 修改金额");
        this.money = money;
    }
    
    //只读属性
    public double getMoney() { return money; }
}

封装优势:​

  • 数据访问可控
  • 支持数据验证
  • 方便添加日志/通知等横切关注点
  • 保持接口稳定性

三、构造方法与对象初始化

3.1 构造方法类型

//文档10构造方法示例
public class Person {
    //无参构造
    public Person() {
        System.out.println("默认构造");
    }
    
    //全参构造
    public Person(String name, char sex, int age) {
        System.out.println("全参构造");
        this.name = name;
        this.sex = sex;
        this.age = age;
    }
}

构造方法特点:​

  • 方法名必须与类名相同
  • 无返回类型声明
  • 支持方法重载
  • 默认提供无参构造(当无自定义构造时)
  • this()可调用同类其他构造方法

3.2 对象初始化顺序

//文档9构造方法测试
Person p = new Person("李四", 'M', 25); 
// 输出顺序:
// 1. 父类构造(如果有)
// 2. 成员变量初始化
// 3. 构造方法体执行

初始化顺序:​

  1. 静态初始化块(类加载时)
  2. 实例初始化块(每次new时)
  3. 构造方法执行
  4. 父类构造优先于子类

四、高级特性补充

4.1 静态成员

public class Person {
    //静态计数器
    private static int count = 0;
    
    public Person() {
        count++;
    }
    
    public static int getCount() {
        return count;
    }
}

静态特性:​

  • 类级别共享数据
  • 通过类名直接访问
  • 静态方法不能访问非静态成员
  • 静态初始化块用于复杂初始化

4.2 继承与多态

//补充继承示例
public class Student extends Person {
    private String school;
    
    @Override
    public void eat() {
        System.out.println("学生在食堂吃饭");
    }
}

继承要点:​

  • extends实现继承
  • super调用父类成员
  • 方法重写规则(@Override)
  • 里氏替换原则

4.3 接口与实现

//补充接口示例
public interface Walkable {
    void walk(int speed);
}

public class Athlete extends Person implements Walkable {
    @Override
    public void walk(int speed) {
        System.out.println("运动员竞走速度:" + speed);
    }
}

接口特性:​

  • 完全抽象(JDK8前)
  • 多实现机制
  • 默认方法(default)
  • 静态接口方法

五、面向对象设计原则

5.1 SOLID原则

  1. 单一职责:User类不应包含支付逻辑
  2. 开闭原则:通过继承扩展功能而非修改类
  3. 里氏替换:子类可完全替代父类
  4. 接口隔离:多个专用接口优于单一总接口
  5. 依赖倒置:高层模块不应依赖低层细节

5.2 设计模式示例

//简单工厂模式
public class PersonFactory {
    public static Person createPerson(String type) {
        switch(type) {
            case "student": return new Student();
            case "teacher": return new Teacher();
            default: return new Person();
        }
    }
}

六、异常处理补充

//封装中的异常处理
public void setAge(int age) throws IllegalArgumentException {
    if(age < 0 || age > 150) {
        throw new IllegalArgumentException("无效年龄");
    }
    this.age = age;
}

最佳实践:​

  • 在setter中进行参数校验
  • 使用自定义异常类型
  • 保持对象状态有效性

十、this 关键字相关

一. this 的三大核心作用

public class Person {
    public Person(String name, char sex, int age) {
        this.name = name;       // 1. 区分成员变量与局部变量
        this.sex = sex;
        this.age = age;
    }

    public void study() {
        this.eat();             // 2. 调用同类其他方法
        this.writerCode();
    }
}
public class User {
    public User() {
        this("default", "000000"); // 3. 调用其他构造方法(必须首行)
    }
}
核心知识点
  • 成员变量遮蔽:当形参与成员变量同名时,用 this.变量名 明确指向对象属性
  • 方法间调用:在实例方法中,this 可调用本类其他方法(非必须但增强可读性)
  • 构造方法链:通过 this(参数) 重用构造逻辑,需在构造方法首行使用

二、static 关键字相关

1. 静态变量 vs 实例变量

描述局部变量实例变量
定义位置方法或方法内的结构当中类的内部,方法的外部
默认值无默认值有默认值(与数组相同)
使用范围从定义行到包含其结构结束本类有效
命名冲突不允许重名可与局部变量重名,局部变量优先
存储位置基本数据类型存在栈中,引用数据类型名字在栈,值在堆因为实例属性保存在对象中,而对象存在堆中,全部存储在堆中
生命周期随着方法的入栈而生效,随着方法的出栈而死亡随着对象的创建而存在 随着对象被垃圾回收(GC)而死亡
public class A {
    String attr01;          // 实例变量(对象级)
    static String attr02;   // 静态变量(类级)
}
核心知识点
  • 存储位置:静态变量在方法区,实例变量在堆内存
  • 生命周期:静态变量随类加载存在,实例变量随对象创建/销毁
  • 访问方式
    A.attr02 = "value";      // 推荐类名访问
    new A().attr01 = "val";  // 必须通过对象

2. 类加载与初始化顺序

// 文档6:static A a = new A() 先执行
static A a = new A();     // 触发构造方法执行
static int value1;
static int value2 = 0;

// 构造方法中对静态变量自增
public A() {
    value1++;  // 结果:value1=1
    value2++;  // 先变成1,后被显式初始化为0
}
执行顺序解析
  1. 准备阶段:静态变量默认初始化(a=nullvalue1=0value2=0
  2. 初始化阶段:
    • 按代码顺序执行:
      • new A() → 构造方法使 value1=1value2=1
      • value2=0 覆盖为0
  3. 最终结果:value1=1value2=0

三、代码块执行顺序

1. 代码块类型与特性

public class A {
    static { // 静态代码块(类加载时执行一次)
        attr02 = "CCC"; 
    }
    
    { // 实例代码块(每次new对象时执行,先于构造方法)
        attr01 = "bbb";
    }

    public A() { // 构造方法最后执行
        attr01 = "aaa";
    }
}
执行顺序验证
new A(); // 输出顺序:
// 1. 静态代码块输出 → "CCC"
// 2. 实例代码块输出 → "bbb -- BBB"
// 3. 构造方法输出 → "aaa -- AAA"

四、工具类设计模式

1. 工具类最佳实践

public class MyArrays {
    private MyArrays() {} // 禁止实例化

    public static int[] copyOf(int[] arr, int newLength) {
        // 实现数组复制逻辑
    }

    public static String toString(int[] arr) {
        // 实现数组转字符串
    }
}
设计要点
  • 私有构造方法:防止通过 new 创建实例
  • 全静态方法:通过类名直接调用(如 MyArrays.copyOf()
  • 功能完整性
    • 处理不同长度需求(扩容/截断)
    • 格式规范化输出(模仿 Arrays.toString()

五、补充关键知识点

1. 类加载机制

  • 加载 → ​验证 → ​准备 → ​解析 → ​初始化
  • 静态变量准备阶段赋默认值,初始化阶段赋真实值

2. 单例模式与静态变量

class Singleton {
    private static Singleton instance = new Singleton();
    private Singleton() {}
}

3. 方法设计建议

  • 参数校验:工具方法应添加 if (arr == null) throw...
  • 异常处理:考虑添加 IllegalArgumentException

六、易错点总结

场景常见错误正确做法
构造方法链this() 不在首行必须作为构造方法第一条语句
静态变量访问通过对象访问静态变量使用类名访问
代码块顺序混淆静态/实例代码块执行顺序记住静态→父类→实例→构造方法

 

十一、继承基础

1.1 继承结构

// 文档1:Person基类
public class Person {
    String name;
    char sex;
    int age;
    
    public Person() {
        System.out.println("Person构造");
    }
    
    public void eat(){}
    public void sleep(){}
}

// 文档3:Chinese子类
public class Chinese extends Person{
    String id;
    
    public Chinese() {
        System.out.println("Chinese构造");
    }
    
    public void playTaiJi(){}
}

1.2 核心知识点

  1. 继承机制:子类继承父类非私有成员(字段+方法)
  2. 构造方法执行顺序
    • 父类构造方法先于子类执行
    • 默认调用super()(隐式调用父类无参构造)
  3. 继承链
    Person构造 -> Chinese构造

二、构造方法链

2.1 构造方法示例

// 文档10:带参数的构造方法
public Chinese(String name, char sex, int age, String id) {
    super(name, sex, age); // 显式调用父类构造
    this.id = id;
}

2.2 关键要点

  1. super()规则
    • 必须作为子类构造方法的第一条语句
    • 父类若无无参构造,必须显式调用其他构造
  2. 构造方法执行顺序
    • 父类字段初始化 -> 父类构造方法体 -> 子类字段初始化 -> 子类构造方法体

三、访问权限控制

3.1 权限修饰符对比

修饰符同类同包子类其他包
private✔️✖️✖️✖️
default✔️✔️✖️✖️
protected✔️✔️✔️✖️
public✔️✔️✔️✔️

3.2 典型示例

// 文档6:A类
public class A {
    private String attr = "A属性";
    protected void method02(){}
}

// 文档7:B类(子类)
public class B extends A {
    public void test() {
        // super.attr; // 错误!不能访问父类私有成员
        super.method02(); // 允许访问protected方法
    }
}

四、方法重写(Override)

4.1 重写规则

  1. 方法签名相同
  2. 访问权限不能更严格
  3. 返回类型相同
  4. 异常不能扩大

4.2 注解使用

// 文档15:eat方法重写
@Override
public void eat() {
    System.out.println(super.getName() + "吃中餐");
}

4.3 特殊方法重写

  1. equals()
    // 文档24:User类重写
    @Override
    public boolean equals(Object obj) {
        if(this == obj) return true;
        if(obj instanceof User){
            return this.username.equals(((User)obj).username);
        }
        return false;
    }
  2. toString()
    @Override
    public String toString() {
        return username + "--" + password;
    }

五、Object类核心方法

5.1 重要方法解析

方法说明
equals()默认比较对象地址,需重写实现内容比较
hashCode()返回对象哈希码,重写equals时必须同时重写
toString()返回对象字符串表示,默认格式:类名@十六进制哈希码
getClass()返回运行时类对象
clone()创建并返回对象副本(需实现Cloneable接口)

5.2 典型应用

// 文档27:自定义字符串比较
public class MyString {
    @Override
    public boolean equals(Object obj) {
        // 内容比较逻辑
    }
}

六、封装与多态

6.1 封装实现

// 文档8:Person类封装
public class Person {
    private String name;
    // 通过getter/setter访问
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
}

6.2 多态应用

// 文档12:方法重写实现多态
public class Japanese extends Person {
    @Override
    public void eat() {
        System.out.println("吃日料");
    }
}

七、特殊语法特性

7.1 super关键字

  1. 访问父类成员
    super.getName();
  2. 调用父类构造
    super(name, sex, age);

7.2 final关键字

  1. 修饰类:不可继承
  2. 修饰方法:不可重写
  3. 修饰变量:常量

八、字符串处理

8.1 String特殊性

  1. 不可变性:任何修改都会创建新对象
  2. 字符串池:字面量共享机制
  3. 比较方法
    String s1 = new String("abc");
    String s2 = "abc";
    System.out.println(s1 == s2); // false
    System.out.println(s1.equals(s2)); // true

九、综合案例解析

9.1 用户系统实现

// 文档24-25:用户类及测试
public class User {
    // 字段封装
    // equals/toStirng重写
}

public class Test01 {
    public static void main(String[] args) {
        User u1 = new User("user1", "123", "张三", 5000);
        User u2 = new User("user1", "456", "李四", 3000);
        System.out.println(u1.equals(u2)); // true(用户名相同)
    }
}

相关文章:

  • Linux安装Idea
  • Vue3中的Icon处理方案(包括将svg转化为Icon)
  • 单北斗:构筑自主时空基准,赋能数字中国新未来
  • linux0.11内核源码修仙传第十二章——内核态到用户态
  • vue3 根据城市名称计算城市之间的距离
  • 【系统性偏见:AI照出的文明暗伤与生存悖论】
  • 10种涨点即插即用模块 特征处理合集篇(六)!!!(附原文地址+论文+代码)
  • Using SAP an introduction for beginners and business users
  • 磁盘结构损坏防护与应对全解析:从风险预警到数据拯救的关键策略
  • git push origin masterremote: [session-bd46a49f] The token username invalid
  • kaggle共享单车预测
  • 当 EcuBus-Pro + UTA0401 遇上 NSUC1500
  • C++/数据结构:哈希表知识点
  • Redis BitMap 实现签到及连续签到统计
  • Dart之库和可见性和异步支持、生成器、可调用类与Isolates、Typedefs和元数据
  • 微前端 - 以无界为例
  • C语言库zlog日志库工具
  • 23种设计模式-结构型模式-组合
  • RabbitMQ消息队列面试题集合
  • 如何使用 FastAPI 构建 MCP 服务器
  • 网站建设优化兼职在家/关键词推广效果分析
  • 做网站有哪个软件好/站内推广方式有哪些
  • 123883网站/seo关键词排名优化软件怎么选
  • 新网站建设方案ppt/自媒体平台注册下载
  • 怎么做自己的网站推广产品/百度seo课程
  • html网页设计表格代码范文/seo软件哪个好