1.this关键字

1.可以调用的结构:属性、方法;构造器

2.this调用属性、方法:

this理解为:当前对象或当前正在创建的对象
2.1 在类的方法中,我们可以使用”this.属性”或”this.方法”的方式,调用当前对象属性或方法。但是,通常情况下,我们都选择省略”this.”。特殊情况下,如果方法的形参和类的属性同名时,我们必须显式的使用"this.变量"的方式,表明此变量是属性,而非形参。
​ 2.2 在类的构造器中,我们可以使用”this.属性”或”this.方法”的方式,调用当前正在创建的对象属性或方法。但是,通常情况下,我们都选择省略”this.”。特殊情况下,如果构造器的形参和类的属性同名时,我们必须显式的使用"this.变量"的方式,表明此变量是属性,而非形参。

3.this调用构造器:

① 我们在类的构造器中,可以显式的使用”this(形参列表)”方式,调用本类中指定的其他构造器
② 构造器中不能通过”this(形参列表)”方式调用自己
③ 如果一个类中有n个构造器,则最多有 n - 1构造器中使用了”this(形参列表)”(因为有默认的无参构造器)
规定:"this(形参列表)"必须声明在当前构造器的首行
⑤ 构造器内部,最多只能声明一个”this(形参列表)”,用来调用其他的构造器

2. package 与 import 关键字的使用

1. package的使用

  • 为了更好的实现项目中类的管理,提供包的概念

  • 使用package声明类或接口所属的包,声明在源文件的首行

  • 包,属于标识符,遵循标识符的命名规则、规范(xxxyyyzzz)、“见名知意”

  • 每”.”一次,就代表一层文件目录。

    2. import的使用

import:导入
2.1. 在源文件中显式的使用import结构导入指定包下的类、接口
2.2. 声明在包的声明和类的声明之间
2.3. 如果需要导入多个结构,则并列写出即可
2.4. 导入"xxx.yy",表示可以导入 yy 包下的所有结构,但是如果使用的是xxx子包下的结构,则仍需要显式导入(yy表示类或接口)。

2.5 如果使用的类或接口是java.lang包下定义的,则可以省略import结构。

2.6 如果使用的类或接口是本包下定义的,则可以省略import结构。

2.7 如果在源文件中,使用了不同包下的同名的类,则必须至少一个类需要以全类名的方式示。

2.8import static:导入指定类或接口中的静态结构:属性或方法。

3.super关键字调用父类属性、方法、构造器

1.super 关键字可以理解为:父类的

2.可以用来调用的结构:

属性、方法、构造器

3.super调用属性、方法:

​ 3.1 我们可以在子类的方法或构造器中。通过使用”super.属性”或”super.方法”的方式,显式的调用父类中声明的属性或方法。但是,通常情况下,我们习惯省略"super."
​ 3.2 特殊情况:当子类和父类中定义了同名的属性时,我们要想在子类中调用父类中声明的属性,则必须显式的使用”super.属性”的方式,表明调用的是父类中声明的属性。
​ 3.3 特殊情况:当子类重写了父类中的方法以后,我们想在子类的方法中调用父类中被重写的方法时,则必须显式的使用”super.方法”的方式,表明调用的是父类中被重写的方法。

4.super调用构造器:

​ 4.1 我们可以在子类的构造器中显式的使用”super(形参列表)”的方式,调用父类中声明的指定的构造器
​ 4.2 “super(形参列表)”的使用,必须声明在子类构造器的首行!
​ 4.3 我们在类的构造器中,针对于"this(形参列表)"或"super(形参列表)"只能二选一,不能同时出现
​ 4.4 在构造器的首行,没显式的声明”this(形参列表)”或”super(形参列表)”,则默认调用的是父类中空参的构造器:super()
​ 4.5 在类的多个构造器中,至少一个类的构造器中使用了”super(形参列表)”,调用父类中的构造器

4.关键字 static 修饰属性、方法

static:静态的

1.可以用来修饰的结构:主要用来修饰类的内部结构

属性、方法、代码块、内部类

2.static修饰属性:静态变量(或类变量)

​ 2.1 属性,是否使用static修饰,又分为:静态属性 vs 非静态属性(实例变量)
实例变量:我们创建了类的多个对象,每个对象都独立的拥一套类中的非静态属性。当修改其中一个对象中的非静态属性时,不会导致其他对象中同样的属性值的修改。
静态变量:我们创建了类的多个对象,多个对象共享同一个静态变量。当通过某一个对象修改静态变量时,会导致其他对象调用此静态变量时,是修改过了的。
​ 2.2 static修饰属性的其他说明:
① 静态变量随着类的加载而加载。可以通过”类.静态变量”的方式进行调用
​ ② 静态变量的加载要早于对象的创建。
​ ③ 由于类只会加载一次,则静态变量在内存中也只会存在一份:存在方法区的静态域中。

​ ④ 类变量 实例变量
​ 类 yes no
​ 对象 yes yes

​ 第4次出现JVM内存结构

JVM内存结构4

​ 2.3 静态属性举例:System.out; Math.PI;

3.静态变量内存解析:

jdk6及之前,存放在方法区。jdk7及之后,存放在堆空间
以修饰属性为例
image-20250614235133727

4.static修饰方法:静态方法、类方法

​ ① 随着类的加载而加载,可以通过”类.静态方法”的方式进行调用

​ ②

能否调用 静态方法 非静态方法
yes no
对象 yes yes

③ 静态方法中,只能调用静态的方法或属性
非静态方法中,既可以调用非静态的方法或属性,也可以调用静态的方法或属性

5.static的注意点:

1 在静态的方法内,不能使用this关键字、super关键字
2 关于静态属性和静态方法的使用,大家都从生命周期的角度去理解。

6.如何判定属性和方法应该使用static关键字:

1 关于属性

属性是可以被多个对象所共享的,不会随着对象的不同而不同的。
类中的常量也常常声明为static。

2 关于方法

操作静态属性的方法,通常设置为static的
工具类中的方法,习惯上声明为static的。 比如:Math、Arrays、Collections

7.使用举例:

举例一:Arrays、Math、Collections等工具类
举例二:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
class Circle{

private double radius;
private int id;//自动赋值

public Circle(){
id = init++;
total++;
}

public Circle(double radius){
this();

// id = init++;
// total++;
this.radius = radius;

}

private static int total;//记录创建的圆的个数
private static int init = 1001;//static声明的属性被所对象所共享

public double findArea(){
return 3.14 * radius * radius;
}

public double getRadius() {
return radius;
}

public void setRadius(double radius) {
this.radius = radius;
}

public int getId() {
return id;
}

public static int getTotal() {
return total;
}

}

5. 关键字 final

final:最终的

1.可以用来修饰:类、方法、变量

2.具体的

​ 2.1 final 用来修饰一个类:此类不能被其他类所继承。
​ 比如:String类、System类、StringBuffer类

​ 2.2 final 用来修饰方法:表明此方法不可以被重写
比如:Object类中getClass();

​ 2.3 final 用来修饰变量:此时的”变量”就称为是一个常量
2.3.1 final修饰属性:可以考虑赋值的位置:显式初始化、代码块中初始化、构造器中初始化
2.3.2 final修饰局部变量:
​ 尤其是使用final修饰形参时,表明此形参是一个常量。当我们调用此方法时,给常量形参赋一个实参。一旦赋值以后,就只能在方法体内使用此形参,但不能进行重新赋值。

  •       static final 用来修饰属性:全局常量
    

6. 子类对象实例化的全过程

1.从结果上看:继承性

子类继承父类以后,就获取了父类中声明的属性或方法。
创建子类的对象,在堆空间中,就会加载所有父类中声明的属性。

2.从过程上看:

当我们通过子类的构造器创建子类对象时,我们一定会直接或间接的调用其父类的构造器,进而调用父类的父类的构造器,...直到调用了java.lang.Object类中空参的构造器为止。正因为加载过所有的父类的结构,所以才可以看到内存中父类中的结构,子类对象才可以考虑进行调用。
图示:
image-20250614235155343

3.强调说明:

虽然创建子类对象时,也调用了父类的构造器,但是自始至终就创建过一个对象,即为new的子类对象(没new不算创建对象)。

image-20250614235325195

7. Object 类及 clone()、finalize()的理解

java.lang.Object类的说明:

1.Object类是所有Java类的根父类

2.如果在类的声明中未使用extends关键字指明其父类,则默认父类为java.lang.Object类

3.Object类中的功能(属性、方法)具有通用性。

​ 属性:无
​ 方法:equals() / toString() / getClass() /hashCode() / clone() / finalize()
​ finalize():当垃圾收集器准备回收一个对象时,它会首先调用该对象的 finalize() 方法。这个方法的默认实现是空的,但你可以在你自己的类中覆盖这个方法,以便在对象被销毁前执行一些必要的清理工作,比如关闭文件、释放资源等。

​ 与线程相关的方法: wait() 、 notify()、notifyAll()后面会详细讲

4.Object类只声明了一个空参的构造器

它存在的目的是为了让所有的子类在创建对象时都能够通过默认构造器进行初始化。

8. equals()方法的使用

equals()方法

1 .equals()的使用:

1.1是一个方法,而非运算符
1.2. 只能适用于引用数据类型
1.3. Object类中equals()的定义:

1
2
3
4
//就是调用==与自己比较,因为是引用数据类型,所以就是比较地址值
public boolean equals(Object obj) {
return (this == obj);
}

说明:Object类中定义的equals()和==的作用是相同的:比较两个对象的地址值是否相同.即两个引用是否指向同一个对象实体

​ 1.4. 像String、Date、File、包装类等都重写了Object类中的equals()方法。重写以后,比较的不是两个引用的地址是否相同,而是比较两个对象的”实体内容”是否相同。(有兴趣自己看源码)
​ 1.5. 通常情况下,我们自定义的类如果使用equals()的话,也通常是比较两个对象的"实体内容"是否相同。那么,我们就需要对Object类中的equals()进行重写
重写的原则:比较两个对象的实体内容是否相同.

2 .如何重写equals()

2.1 手动重写举例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class User{
String name;
int age;
//重写其equals()方法
public boolean equals(Object obj){
if(obj == this){
return true;
}
if(obj instanceof User){
User u = (User)obj;
return this.age == u.age && this.name.equals(u.name);
}
return false;
}
}

2.2 开发中如何实现:自动生成的
2.3 补充

== 符号使用时,必须保证符号左右两边的变量类型一致。

9.toString()方法的使用

toString()方法

1.toString()的使用:

1.1当我们输出一个对象的引用时,实际上就是调用当前对象的toString()

1.2. Object类中toString()的定义:

1
2
3
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}

1.3. 像String、Date、File、包装类等都重写了Object类中的toString()方法。使得在调用对象的toString()时,返回"实体内容"信息

1.4. 自定义类也可以重写toString()方法,当调用此方法时,返回对象的”实体内容”

2.如何重写toString()

举例:

1
2
3
4
5
//自动实现
@Override
public String toString() {
return "Customer [name=" + name + ", age=" + age + "]";
}