equals方法
equals 和 == 的区别
- == 是一个比较运算符,它可以判断基本类型,也可以判断引用类型。如果判断基本类型,判断的是值是否相等;如果判断的是引用类型,实际上判断的是地址是否相等,即判定是不是堆内存里的同一个对象
- equals 是 Object 类中的方法,只能判断引用类型,Object 中的 equals 方法默认判断的是地址是否相等,和 == 号判断引用类型一样,但子类中往往会重写 equals 方法,用于判断内容是否相等。如 Integer、String 类就重写了 equals 方法
重写 Person 类中的 equals 方法
判断两个 Person 对象的内容是否相等,如果两个 Person 对象的各个属性值都一样,返回 true ,反之返回 false 。
public class Test {
public static void main(String[] args) {
Person p1 = new Person("zs", 28, '男');
Person p2 = new Person("zs", 28, '男');
System.out.println(p1.equals(p2));
}
}
class Person {
private String name;
private int age;
private char gender;
public Person(String name, int age, char gender) {
this.name = name;
this.age = age;
this.gender = gender;
}
// .... 省略属性的 get 和 set 方法
// 重写 Object 中的 equals 方法
public boolean equals(Object obj){
// 如果比较的两个对象是同一个对象,返回 true
if(this == obj) {
return true;
}
// 如果 obj 是 Person 类的实例对象
if(obj instanceof Person){
// 向下转型,因为需要用到 Person 中的属性
Person p = (Person)obj;
return this.name.equals(p.name) && this.age == p.age && this.gender == p.gender;
}
// 如果不是 Person 类实例对象,直接返回 false
return false;
}
}
hashCode 方法
- hashCode 方法能提高具有哈希结构的容器的效率
- 如果两个对象引用,指向的是同一个对象,则哈希值肯定是一样的
- 如果两个对象引用,指向的是不同对象,一般情况下哈希值是不一样的(如果一样就是发生了碰撞)
- 哈希值主要是根据地址号来得到的,但是 java 是在虚拟机上运行的,不能得到真实的物理地址,所以不能完全将哈希值等价于地址
public class Test {
public static void main(String[] args) {
AA a1 = new AA();
AA a2 = new AA();
AA a3 = a1;
// a1 和 a2 指向不同对象,所以哈希值不同
// a1 和 a3 指向相同对象,所以哈希值相同
System.out.println(a1.hashCode()); // 1763847188
System.out.println(a2.hashCode()); // 1617791695
System.out.println(a3.hashCode()); // 1763847188
}
}
class AA {}
toString 方法
基本介绍
调用 toString 方法默认会返回:全类名(包名 + 类名)+ @ + 哈希值的十六进制,子类往往会重写 Object 中的 toString 方法,用于返回对象的属性信息。打印对象或拼接对象时,都会自动调用该对象的 toString 形式。 Object 类中的 toString 方法源码如下:
// Object 中的 toString 方法
public String toString(){
return getClass().getName() + '@' + Integer.toHexString(hashCode());
}
重写 toString 方法
public class Test {
public static void main(String[] args) {
Person p = new Person("zs", 18, '男');
// 重写 toString 前,调用 toString 方法默认会返回:全类名(包名 + 类名)+ @ + 哈希值的十六进制
// 当前文件不在包下,所以没有打印包名
System.out.println(p.toString()); // Person@69222c14
// 打印对象或拼接对象时,都会自动调用该对象的 toString 形式
// 直接打印 p 对象和 p.toString 等价
System.out.println(p); // Person@69222c14
// 重写 toString 方法后
System.out.println(p.toString()); // name=zs age=18 gender=男
}
}
class Person {
private String name;
private int age;
private char gender;
public Person(String name, int age, char gender) {
this.name = name;
this.age = age;
this.gender = gender;
}
// .... 省略属性的 get 和 set 方法
// 重写 Object 中的 toString 方法
// 子类往往会重写 Object 中的 toString 方法,用于返回对象的属性信息。
public String toString(){
return "name=" + name + " age=" + age + " gender=" + gender;
}
}
finalize 方法
-
当对象被回收时,系统自动调用该对象的 finalize 方法。子类可以重写该方法,做一些释放资源的操作
-
对象被回收的时机:当某个对象没有任何引用时,则 JVM 就认为这个对象是一个垃圾对象,就会使用垃圾回收机制来销毁该对象,在销毁该对象前,会先调用 finalize 方法
-
垃圾回收机制的调用,是由系统来决定,也可以通过 System.gc() 主动触发垃圾回收机制
class Finalize {
public static void main(String[] args) {
Car car = new Car("玛莎拉蒂");
/*
* 把 car 置空后, new Car("玛莎拉蒂") 出来的对象就没有被引用,成为了一个垃圾
* 垃圾回收机制会根据回收算法对该对象进行销毁,在销毁前会对调用 finalize 方法
* 由于系统是根据算法进行回收的,所以当某个对象成为垃圾后,系统不会马上进行回收
* 可以调用 System.gc() 方法主动触发垃圾回收机制,执行该方法后不会进行阻塞,而是会继续往下执行代码
* 调用 System.gc() 方法后不一定能百分百成功回收对象,还要受系统等因素影响
* 如果程序员有自己的需求,可以重写 finalize 方法,在方法里实现自己的业务逻辑
* 如果不重写,就会自动调用 Object 中的 finalize 方法,即默认处理
*/
car = null;
/*
* 执行 System.gc() 方法后不会进行阻塞,而是会继续往下执行代码
* 输出:
* 代码执行完毕...
* 销毁 玛莎拉蒂 对象
*/
System.gc();
System.out.println("代码执行完毕...");
}
}
class Car {
public String name;
public Car(String name){
this.name = name;
}
// 重写 finalize 方法
protected void finalize() throws Throwable {
System.out.println("销毁 玛莎拉蒂 对象");
// 执行其他业务逻辑...
}
}