java基础笔记
Java 复习篇 1
0.java特性
1.封装
封装是面向对象编程的一个基本特性,它指的是将对象的状态(属性)和行为(方法)封装在一起,并控制对这些状态的访问。通过封装,可以保护对象的内部状态,避免直接访问和修改,从而提高代码的安全性和可维护性。
1
2
3
4
5**访问控制**:通过访问修饰符(如 `private`、`protected` 和 `public`)来控制对类成员的访问。
**数据隐藏**:将对象的内部状态隐藏在类的外部,防止外部直接访问。
**提供公共方法**:通过公共方法(如 getter 和 setter)来允许外部访问和修改对象的属性。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23public class Person {
private String name;
private int gender;
private int age;
public String getName() {
return name;
}
public String getGender() {
return gender == 0 ? "man" : "woman";
}
public void work() {
if (18 <= age && age <= 50) {
System.out.println(name + " is working very hard!");
} else {
System.out.println(name + " can't work any more!");
}
}
}
2.继承
继承实现了 IS-A 关系,例如 Cat 和 Animal 就是一种 IS-A 关系,因此 Cat 可以继承自 Animal,从而获得 Animal 非 private 的属性和方法。
继承应该遵循里氏替换原则,子类对象必须能够替换掉所有父类对象。
Cat 可以当做 Animal 来使用,也就是说可以使用 Animal 引用 Cat 对象。父类引用指向子类对象称为 向上转型 。
向下转型
Dog dog = (Dog) animal; //
dog.dogsu()->出现访问错误 不安全
3.多态
多态分为编译时多态和运行时多态:
- 编译时多态主要指方法的重载
- 运行时多态指程序中定义的对象引用所指向的具体类型在运行期间才确定
运行时多态有三个条件:
- 继承
- 覆盖(重写)
- 向上转型
1 | |
1.基础篇
1.Jvave开发环境
Java应用程序通常被编译为可在任何Java虚拟机(JVM)上运行的字节码
Jdk->Java开发工具包 jre 运行环境 Jvm java虚拟机->转换字节码文件->本地机器码
2.基本数据类型
1.内置
byte -short-int-long float-double boolean char
基本类型都有对应的包装类型,基本类型与其对应的包装类型之间的赋值使用自动装箱与拆箱完成。
2.缓冲池
new Integer(123) 与 Integer.valueOf(123) 的区别在于:
- new Integer(123) 每次都会新建一个对象
- Integer.valueOf(123) 会使用缓存池中的对象,多次调用会取得同一个对象的引用。
1 | |
1 | |
如果再缓冲池就之间返回对象引用-如果不在就new一个
3.字符串
String 被声明为 final,因此它不可被继承。
内部使用 char 数组存储数据,该数组被声明为 final,这意味着 value 数组初始化之后就不能再引用其它数组。并且 String 内部没有改变 value 数组的方法,因此可以保证 String 不可变。
1 | |
1 | |
1.不可变特性探究
我们有可变的字符串了,那么对比不可变的好处
1. 可以缓存 hash 值
因为 String 的 hash 值经常被使用,例如 String 用做 HashMap 的 key。不可变的特性可以使得 hash 值也不可变,因此只需要进行一次计算。
2. String Pool 的需要
如果一个 String 对象已经被创建过了,那么就会从 String Pool 中取得引用。只有 String 是不可变的,才可能使用 String Pool。

3.安全性
String 经常作为参数,String 不可变性可以保证参数不可变。例如在作为网络连接参数的情况下如果 String 是可变的,那么在网络连接过程中,String 被改变,改变 String 对象的那一方以为现在连接的是其它主机,而实际情况却不一定是。
4.线程安全
string不可变
2.String, StringBuffer and StringBuilder

3.string.intern
使用 String.intern() 可以保证相同内容的字符串变量引用同一的内存对象。
s1 和 s2 采用 new String() 的方式新建了两个不同对象,而 s3 是通过 s1.intern() 方法取得一个对象引用。intern() 首先把 s1 引用的对象放到 String Pool(字符串常量池)中,然后返回这个对象引用。因此 s3 和 s1 引用的是同一个字符串常量池的对象。
1 | |
如果是采用 “bbb” 这种使用双引号的形式创建字符串实例,会自动地将新建的对象放入 String Pool 中。
- HotSpot中字符串常量池保存哪里?永久代?方法区还是堆区?

2.引用
类似CPP的指针->指向了存储的真实地址 -对象 数组
ps:
1.常量-final -指定后无法更改
2.类型转换-大转小-精度丢失–强制转 小转大-自动
2.1标识符
java中规定只能使用数字 ,字母 ,美元符号, 下划线作为标识符。
不能重复。所以关键字、预定义标识符不能作为用户标识符。
允许的长度是由具体的编译器决定。
区分大小写。
不推荐用双下划线开头因为预定义标识符一般用双下划线开头。关键字你能背下来但是预定义标识符没人会去背。万一重了不好办。
3.Jave变量类型
- 类变量:独立于方法之外的变量,用 static 修饰。-静态存储区-
- 示例变量:独立于方法之外的变量,不过没有 static 修饰。
- 局部变量:类的方法中的变量。–堆栈中开辟
什么时候销毁-
4.Java运算符
算术运算符
+ - * / % ++ – 关系运算符
== != > < >= <= 位运算符
& 如果相对应位都是1,则结果为1,否则为0 (A&B),得到12,即0000 1100 | 如果相对应位都是 0,则结果为 0,否则为 1 (A | B)得到61,即 0011 1101 ^ 如果相对应位值相同,则结果为0,否则为1 (A ^ B)得到49,即 0011 0001 〜 按位取反运算符翻转操作数的每一位,即0变成1,1变成0。 (〜A)得到-61,即1100 0011 << 按位左移运算符。左操作数按位左移右操作数指定的位数。 A << 2得到240,即 1111 0000 >> 按位右移运算符。左操作数按位右移右操作数指定的位数。 A >> 2得到15即 1111 >>> 按位右移补零操作符。左操作数的值按右操作数指定的位数右移,移动得到的空位以零填充。 A>>>2得到15即0000 1111 逻辑运算符
&& | | ! 赋值运算符
省
其他运算符
1.三元运算符
variable x = (expression) ? value if true : value if falseString name = "James"; boolean result = name instanceof String; // 由于 name 是 String 类型,所以返回真1
2
3
2.类型比对System.out.println();1
2
3
#### 5.Java输入和输出//创建Scanner对象 Scanner input = new Scanner(System.in);1
//接受用户的输入
int number = input.nextInt();
1 | |
9.循环语句
for -for -each -while
for -each
1 | |
break-跳出循环语句
也就是直接跳出jmp–走到下行代码地址
continue-当前循环跳过语句
10.数组
1.数组
数组是相似类型数据的集合。它是一个容器,用于保存单一类型的数据(值)。例如,您可以创建一个数组,它可以保存100个int类型的值。
1 | |
2.多维数组
3.数组复制
省
11.关键字探究
1.final
1.数据
声明数据为常量,可以是编译时常量,也可以是在运行时被初始化后不能被改变的常量。
- 对于基本类型,final 使数值不变;
- 对于引用类型,final 使引用不变,也就不能引用其它对象,但是被引用的对象本身是可以修改的。
1 | |
2.方法
1 | |
3.类
类不能继承
final关键字不能用来修饰接口被final关键字修饰的类不能被继承,但抽象类存在的意义在于被其它类继承然后实现其内部方法的,这样final和抽象类之间就产生了矛盾。因此,final并不能修饰抽象类,选项A错误,选项B正确。
C选项,重载的实现是编译器根据函数的不同的参数表,对同名函数的名称做修饰,那么对于编译器而言,这些同名函数就成了不同的函数。但重写则是子类方法对父类的方法的延申,即子类不仅继承了父类的方法,还向父类的方法中添加了属于自己的内容,改变了父类方法原本的内容,而final代表了一种不可变,这明显与重写形成了冲突。因此被final修饰的类可以被重载但不能被重写,选项C错误。
2.static
1. 静态变量
- 静态变量: 又称为类变量,也就是说这个变量属于类的,类所有的实例都共享静态变量,可以直接通过类名来访问它;静态变量在内存中只存在一份。
- 实例变量: 每创建一个实例就会产生一个实例变量,它与该实例同生共死。
1 | |
2.静态方法
静态方法在类加载的时候就存在了,它不依赖于任何实例。所以静态方法必须有实现,也就是说它不能是抽象方法(abstract)。
1 | |
只能访问所属类的静态字段和静态方法,方法中不能有 this 和 super 关键字。
1 | |
3.静态语句块
静态语句块在类初始化时运行一次。
1 | |
4.静态内部类
非静态内部类依赖于外部类的实例,而静态内部类不需要。
1 | |
5.静态导包
在使用静态变量和方法时不用再指明 ClassName,从而简化代码,但可读性大大降低。
1 | |
6.初始化顺序
静态变量和静态语句块优先于实例变量和普通语句块,静态变量和静态语句块的初始化顺序取决于它们在代码中的顺序。
1 | |
最后才是构造函数的初始化。
1 | |
存在继承的情况下,初始化顺序为:
- 父类(静态变量、静态语句块)
- 子类(静态变量、静态语句块)
- 父类(实例变量、普通语句块)
- 父类(构造函数)
- 子类(实例变量、普通语句块)
- 子类(构造函数
2.面向对象篇
1.Java类和对象
类–一个抽象的东西–由一些数据类型组成的抽象东西
对象–实例化后在内存中(堆)中开辟的一块空间
类方法探究
下列说法错误的有( a c d)
A 在类方法中可用this来调用本类的类方法
this是用来引用当前对象的,只有在实例方法中才能使用。类方法(static方法)是属于类的,而不是某个对象的,因此在类方法中不能使用this。B 在类方法中调用本类的类方法时可直接调用
C 在类方法中只能调用本类中的类方法
D 在类方法中绝对不能调用实例方法
类方法不能直接调用实例方法,因为实例方法需要通过具体的对象来调用,而类方法没有绑定到任何对象。
虽然类方法(
static方法)不能直接调用实例方法,但并不意味着类方法完全无法调用实例方法。如果类方法中创建了该类的实例对象,通过该对象是可以调用实例方法的。因此,这一说法并不完全正确。
1
2
3
4
5
6
7
8
9
10class MyClass {
public void instanceMethod() {
System.out.println("这是实例方法");
}
public static void classMethod() {
MyClass obj = new MyClass(); // 创建对象
obj.instanceMethod(); // 通过对象调用实例方法
}
}
2.方法
1 | |
方法到底是什么–方法也是抽象的-也只有在程序运行时 转换为字节码文件
call-oxxxxx->这个地址内就存储着我们方法代码转换的字节码文件
3.构造函数
当类的对象被创建时,该构造函数将被自动调用-并且不返回任何值
4.修饰符
- 访问修饰符
- 非访问修饰符 static final abstract synchronized -无需锁 transient volatile -无需锁
- abstract-抽象类和抽象方法定义
5.字符串
1 | |
| concat() | 将两个字符串连接在一起 |
|---|---|
| equals() | 比较两个字符串的值 |
| charAt() | 返回存在于指定位置的字符 |
| getBytes() | 将字符串转换为字节数组 |
| indexOf() | 返回字符串中指定字符的位置 |
| length() | 返回指定字符串的大小 |
| replace() | 将指定的旧字符替换为指定的新字符 |
| substring() | 返回字符串的子字符串 |
| split() | 将字符串分成字符串数组 |
| toLowerCase() | 将字符串转换为小写 |
| toUpperCase() | 将字符串转换为大写 |
| valueOf() | 返回指定数据的字符串表示形式 |
6.this关键字
在Java中,this关键字用于引用方法或构造函数中的当前对象
–this->指向当前对象地址的一个引用-指针
7.final关键字
在Java中,final关键字用于表示常量。它可以与变量,方法和类一起使用。
任何实体(变量,方法或类)一旦被声明final后,只能分配一次。也就是,
- final变量不能用另一个值重新初始化
- final方法不能被重写
- final类不能被继承
8.instanceof关键字
在Java中,instanceof关键字是二进制运算符。它用于检查对象是否是特定类的实例。
9.递归
在Java中,调用自身的方法称为递归方法。并且,此过程称为递归。
递归优点-简单
缺点–疯狂开堆栈–又疯狂置空
3.面向对象下
1.继承 方法重写 super关键字 抽象类和方法
Java 中有三个访问权限修饰符: private、protected 以及 public,如果不加访问修饰符,表示包级可见。
protected 用于修饰成员,表示在继承体系中成员对于子类可见,但是这个访问修饰符对于类没有意义。
继承
类只能有一个父类,但可以有多个接口
访问父类的构造函数: 可以使用 super() 函数访问父类的构造函数,从而委托父类完成一些初始化的工作。
访问父类的成员: 如果子类重写了父类的中某个方法的实现,可以通过使用 super 关键字来引用父类的方法实现。
方法重写–重写覆盖
抽象类
abstract 抽象类是无法实例化的类 abstract-
抽象类一般会包含抽象方法,抽象方法一定位于抽象类中。
继承抽象类的类 必须实习抽象方法
抽象类可以包含方法的声明和具体实现,可以有构造函数、字段等。
在 Java 中,抽象类中的抽象方法的默认访问权限并不是
public,而是包私有(default),即没有显式指定访问修饰符时,这些方法的访问权限是包内可见的。如果需要将抽象方法设为public,需要明确使用public修饰符。关于访问权限的说法,分析如下:
在Java中,可以将一个类定义在另一个类里面或者一个方法里边,这样的类称为内部类,广泛意义上的内部类一般包括四种:成员内部类,局部内部类,匿名内部类,静态内部类
2.接口
接口中的方法可以有任何合法的参数类型和返回类型,只要它们是 public 或默认访问权限。

接口是抽象类的延伸,在 Java 8 之前,它可以看成是一个完全抽象的类,也就是说它不能有任何的方法实现。
interface-接口声明
-implements -实现实现接口类的方法
接口可以继承其他接口
从 Java 8 开始,接口也可以拥有默认的方法实现,这是因为不支持默认方法的接口的维护成本太高了。在 Java 8 之前,如果一个接口想要添加新的方法,那么要修改所有实现了该接口的类。
接口的成员(字段 + 方法)默认都是 public 的,并且不允许定义为 private 或者 protected。
接口的字段默认都是 static 和 final 的
接口只能包含方法的声明(默认是
public),不能包含具体实现(Java 8 及以后的版本允许有默认方法和静态方法)。
抽象类可以有构造方法,接口不能有(1,8)
抽象类可以包含普通的成员变量,而在 Java 1.8 之前,接口只能包含
public static final常量,即只能有静态常量,不能有普通的成员变量。在 Java 1.8 之前,接口中不能包含静态方法,静态方法是在 Java 1.8 引入的特性。而抽象类是可以包含静态方法的。
Java 中的类可以实现多个接口,但由于 Java 是单继承的,一个类只能继承一个抽象类。
2.1比较

3.多态-方法重载
同一实体(方法,运算符或对象)在不同情况下的行为会有所不同。
多态在汇编中来看-call-函数
这个call是动态计算的-
这也就是动态绑定
在程序执行期间确定将要调用的方法。因此,方法重写是运行时多态。
方法的重写要求方法签名必须一致,包括方法名称、参数列表、返回类型(可以是协变类型,即子类返回类型)。
方法重载
在Java类中,如果参数不同,则可以使用相同的名称创建方法。
方法重载要求方法名相同,且参数的数量、类型或顺序不同。
参数数量不同:可以通过参数的数量来区分重载的方法。
参数类型不同:可以通过参数的类型来区分重载的方法。
参数顺序不同:即使参数类型相同,但如果它们的顺序不同,也可以重载。
应该注意的是,返回值不同,其它都相同不算是重载。
方法的重载。因此,编译可以成功。
也就是编译器。根据参数判断-对呀call
也就是编译阶段把对应call写进去
在方法重写的情况下,方法应该在不同的类中。然而,在方法重载的情况下,方法应该在同一个类中。
方法重写在运行时执行,而方法重载在编译时执行。
向上 子转父 安全
向下 父转子
看范围把
向上 子转父 安全 指针范围调控
向下 父转子 指针范围扩大。访问到不能访问

通过子类对父类方法的覆盖(Override)实现多态:这是最常见的形式。当子类重写(覆盖)父类中的方法时,通过父类的引用调用子类的方法,就体现了多态性。选项 A 是正确的。
利用重载(Overload)来实现多态:在同一个类中定义多个同名但参数不同的方法,也可以被认为是一种多态形式,虽然与覆盖的多态不同。这是编译时多态的一种形式。选项 B 是正确的。
D:错误,子类无法通过重载父类的方法实现多态,重载是在同一个类中进行的。
4.封装
。封装是指将字段和方法绑定在单个类中。
5.嵌套类
另一个类中定义一个类
6.嵌套静态类
//静态嵌套类的对象创建
Animal.Mammal mammal = new Animal.Mammal();
7.Java 匿名类
匿名内部类的作用主要是用来继承其他类或者实现接口,并不需要增加额外的方法,方便对继承的方法进行实现或者重写。
1 | |
我们可以在类的方法中定义匿名类重写匿名类的方法-
若匿名类是接口-我们也需要实现接口
实现-我们匿名类内部有很多逻辑-不想给你看。我们就可以直接对外暴露一个给你让你重写。简单-不需要看其他代码
1 | |
如上-如果我们没有匿名类-我们就需要继承或者接口 Thread来重写run_但匿名类就不需要
匿名类减少了我们代码的复杂程度-用匿名类可以方便对方法或者接口进行重写-(不需要用类继承重写)
8.单例模式
它确保只创建一个类的实例。
设计模式就像我们的代码库一样,其中包含世界各地程序员共享的各种编码技术。
1 | |
单例模式
确保只有一个实例化的对象
也就是需要静态方法 返回已经实例好的对象
返回的对象就可以调用该调用的了
9.枚举
enum Size {
SMALL, MEDIUM, LARGE, EXTRALARGE
}
class Size {
public final static int SMALL = 1;
public final static int MEDIUM = 2;
public final static int LARGE = 3;
public final static int EXTRALARGE = 4;
}
代码多用枚举
10.反射

反射在 Java 中主要有以下几个作用:
- 动态访问类信息:可以在运行时获取类的结构,包括类名、方法、字段和构造函数等。
- 动态实例化对象:可以根据类的名称动态创建对象,而不需要在编译时就确定具体的类。
- 调用方法:能够在运行时调用对象的方法,支持对私有方法的访问。
- 修改字段:可以直接访问和修改对象的属性,即使是私有字段。
- 框架和库支持:许多 Java 框架(如 Spring 和 Hibernate)使用反射来动态处理对象,增强灵活性和可扩展性。
反射允许我们在运行时检查和操作类、接口、构造函数、方法和字段。
Java中有一个名为Class的类,该类在运行时保留有关对象和类的所有信息。
Class对象描述了特定类的属性。该对象用于执行反射。
class 反射-
1 | |
1.反射作用
1.获取接口 -
我们可以使用Class的getInterfaces()方法来收集类实现的接口的信息。此方法返回一个接口数组
1 | |
2.获取超类和访问修饰符
获取超类和访问修饰符
类Class的方法getSuperclass()可用于获取有关特定类的超类的信息。
而且,Class提供了一种getModifier()方法,该方法以整数形式返回class的修饰符。
1 | |
3.反射字段,方法和构造函数
该软件包java.lang.reflect提供了可用于操作类成员的类。例如,
方法类 - 提供有关类中方法的信息
字段类 - 提供有关类中字段的信息
构造函数类 - 提供有关类中构造函数的信息
Java 反射与字段
我们可以使用Field类提供的各种方法检查和修改类的不同字段。
getFields() - 返回该类及其超类的所有公共字段
getDeclaredFields() - 返回类的所有字段
getModifier() - 以整数形式返回字段的修饰符
set(classObject,value) - 使用指定的值设置字段的值
get(classObject) - 获取字段的值
setAccessible(boolean) - 使私有字段可访问
注意:如果我们知道字段名称,则可以使用
getField(“fieldName”) - 从类返回名称为fieldName的公共字段。
getDeclaredField(“fieldName”) - 从类返回名称为fieldName的字段。
1 | |
5.反射 方法
Java 反射与方法
像字段一样,我们可以使用Method类提供的各种方法来检查类的不同方法。
getMethods() - 返回该类及其超类的所有公共方法
getDeclaredMethod() - 返回该类的所有方法
getName() - 返回方法的名称
getModifiers() - 以整数形式返回方法的访问修饰符
getReturnType() - 返回方法的返回类型
1 | |
6.Java 反射与构造函数
我们还可以使用Constructor类提供的各种方法检查类的不同构造函数。
getConstructors() - 返回该类的所有公共构造函数以及该类的超类
getDeclaredConstructor() -返回所有构造函数
getName() - 返回构造函数的名称
getModifiers() - 以整数形式返回构造函数的访问修饰符
getParameterCount() - 返回构造函数的参数数量
示例:构造函数反射
1 | |
11.包
package pkg1[.pkg2[.pkg3…]];
那么它的路径应该是 net/java/util/Something.java 这样保存的。 package(包) 的作用是把不同的 java 程序分类保存,更方便的被其他 java 程序调用。
也就是命名空间 这样变量可以重名
以下是一些 Java 中的包:
java.lang-打包基础的类
java.io-包含输入输出功能的函数
开发者可以自己把一组类和接口等打包,并定义自己的包。而且在实际开发中这样做是值得提倡的,当你自己完成类的实现之后,将相关的类分组,可以让其他的编程者更容易地确定哪些类、接口、枚举和注释等是相关的。
由于包创建了新的命名空间(namespace),所以不会跟其他包中的任何名字产生命名冲突。使用包这种机制,更容易实现访问控制,并且让定位相关类更加简单。
import 关键字
为了能够使用某一个包的成员,我们需要在 Java 程序中明确导入该包。使用 “import” 语句可完成此功能。
3.异常处理

1.异常认识


Throwable-根类
Error
Error表示不可恢复的情况,例如Java虚拟机(JVM)内存不足,内存泄漏,堆栈溢出错误,库不兼容,无限递归等
Exception
程序可以捕获并处理异常。
当方法内发生异常时,它将创建一个对象。该对象称为异常对象。
它包含有关异常的信息,例如异常的名称和说明以及发生异常时的程序状态。


2.异常处理
1 | |
3.异常抛出
1.异常层层抛出 throws
1 | |
1 | |
2.自动抛出异常
1 | |
1 | |
1 | |
3.try with resources
–释放资源还是自己操作– 省
try(new的东西)-当有异常自动给你释放掉
4.注解
—Java注解是我们程序源代码的元数据(有关数据的数据)。
它们向编译器提供关于程序的附加信息,但不是程序本身的一部分
1 | |
1 | |
1 | |
1 | |
该声明指定String类型的非空值的列表。
5.日志-Logging-省
Java允许我们通过日志记录过程来创建和捕获日志消息和文件。
在Java中,日志记录需要框架和API。Java在java.util.logging程序包中具有内置的日志记录框架。
我们还可以将第三方框架(如Log4j,Logback等)用于日志记录。
6.断言
Java中的断言通过测试我们认为是正确的代码来帮助检测错误。
使用assert关键字进行断言
-默认关闭需要启用-
启用断言且条件为时true,程序将正常执行。
但是,如果在启用断言时条件计算为false, JVM会抛出AssertionError,程序会立即停止。
1 | |
4.Object通用方法
来自包体

1 | |

1.equals探究
1 | |
目的:该方法用于判断当前对象是否与另一个对象相等。
默认实现:在 Object 类中,equals 方法通过比较对象的引用来判断两个对象是否相同。
说明文档
等价关系:
equals方法实现了一种等价关系,符合以下性质:自反性(reflexive):任何非空引用
x,x.equals(x)应返回true。1
x.equals(x); // true对称性(symmetric):对于任何非空引用
x和y,x.equals(y)如果返回true,则y.equals(x)也应返回true。1
x.equals(y) == y.equals(x); // true传递性(transitive):对于任何非空引用
x、y和z,如果x.equals(y)和y.equals(z)都返回true,那么x.equals(z)也应返回true。1
2if (x.equals(y) && y.equals(z))
x.equals(z); // true;一致性(consistent):对于任何非空引用
x和y,多次调用x.equals(y)应始终返回相同的结果,前提是用于比较的对象没有被修改。1
x.equals(y) == x.equals(y); // true不等于 null:对于任何非空引用
x,x.equals(null)应返回false。1
x.equals(null); // false;
默认行为:
Object类中的equals方法返回true仅当两个对象的引用相同(即x == y为true)。重写时注意:如果重写
equals方法,通常需要同时重写hashCode方法,以保持哈希码的一般约定:相等的对象必须有相等的哈希码。
equals() 与 ==
- 对于基本类型,== 判断两个值是否相等,基本类型没有 equals() 方法。
- 对于引用类型,== 判断两个变量是否引用同一个对象,而 equals() 判断引用的对象是否等价。
1 | |
代码实现
- 检查是否为同一个对象的引用,如果是直接返回 true;
- 检查是否是同一个类型,如果不是,直接返回 false;
- 将 Object 对象进行转型;
- 判断每个关键域是否相等。
1 | |
2.hashCode
hashCode() 返回散列值,而 equals() 是用来判断两个对象是否等价。等价的两个对象散列值一定相同,但是散列值相同的两个对象不一定等价。
在覆盖 equals() 方法时应当总是覆盖 hashCode() 方法,保证等价的两个对象散列值也相等。
下面的代码中,新建了两个等价的对象,并将它们添加到 HashSet 中。我们希望将这两个对象当成一样的,只在集合中添加一个对象,但是因为 EqualExample 没有实现 hasCode() 方法,因此这两个对象的散列值是不同的,最终导致集合添加了两个等价的对象。
1 | |
3.toString
默认返回 ToStringExample@4554617c 这种形式,其中 @ 后面的数值为散列码的无符号十六进制表示。
1 | |
1 | |
1 | |
4.clone
返回当前副本
注意浅拷贝和深拷贝即可
总结
匿名 -反射-


