toString方法
返回对象的字符串表示形式,其值由类的名称、字符’@’、对象的无符号十六进制哈希码组成
通常建议重写该方法,用于打印对象的基本属性信息
例如:
public class Hello {
public static void main(String[] args) {
Person person = new Person();
System.out.println(person);
//打印该对象时默认调用toString方法
Student student = new Student();
System.out.println(student.toString());
}
}
class Person {}
class Student {
public String name;
public int age;
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
//重写Object的toString方法,打印该对象的属性信息
}
hashCode方法
返回该对象的哈希值,该值用于唯一地标识对象。
例如:
public class Hello {
public static void main(String[] args) {
Person person = new Person();
System.out.println(person.hashCode());
//打印对象person的哈希值
}
}
class Person {
public String name;
public int age;
}
equals方法
用于比较两个对象是否相等,但默认比较的是两个对象的地址,而不是属性
例如:
public class Hello {
public static void main(String[] args) {
Person person1 = new Person("张三",18);
Person person2 = new Person("张三",18);
System.out.println(person1 == person2);
//由于两个对象的地址不同,尽管属性一样,但仍打印false
System.out.println(person1.equals(person2));
//equals方法默认比较的仍是地址,故也打印false
}
}
class Person {
public String name;
public int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
}
hashCode与equals的联系与重写
- 首先需要知道的是hashCode是通过对象的某些属性调用特定的方法生成的哈希值
- equals方法可以进行重写来通过对象的某些属性是否相等判断两个对象是否相等
- 两个相等的对象其哈希值也应该是相等的(注意:哈希值相等的两个对象不一定equals相等)
- 这就意味着hashCode和equals通常是一起重写的
例如:
public class Hello {
public static void main(String[] args) {
Person person1 = new Person("张三",18);
Person person2 = new Person("张三",18);
System.out.println(person1 == person2);
//比较地址,打印为false
System.out.println(person1.equals(person2));
//比较name和age的值,打印true
System.out.println(person1.hashCode() + "--" + person2.hashCode());
//因为参数一样,算法一样,故两个对象的哈希值也是一样的
}
}
class Person {
public String name;
public int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public boolean equals(Object o) {
//两个对象地址相同的情况
if (this == o) return true;
//比较对象为空或两个对象的类不同的情况
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
//比较两个对象的age和name
return age == person.age &&
Objects.equals(name, person.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
//从这里能看出哈希值是通过属性和特定方法获得的
//因此equals为true的对象其哈希值一定一样
//但哈希值是有限的,可能会出现重复的情况
//故哈希值相等的对象其equals不一定为true
}
}
clone方法
克隆,返回一个Object类的对象,该对象的各属性与被克隆对象一致,但并不是同一个对象,这意味克隆出来的对象在堆中有自己独立的地址空间
若想让一个类变为可克隆类,需要重写clone方法,并让该类实现Cloneable接口,该接口中没有任何抽象函数,是一个标识接口
例如:
public class Hello {
//需要抛出或捕获 克隆不被支持异常
public static void main(String[] args) throws CloneNotSupportedException {
Person person1 = new Person("张三",18);
//因为clone返回值为Object类,故需要向下强转
Person person2 = (Person) person1.clone();
//克隆出的对象与被克隆对象地址不同,故哈希值也不同
System.out.println(person1.hashCode() + "--" + person2.hashCode());
//克隆出的对象与被克隆对象属性值相同
System.out.println(person2);
}
}
class Person implements Cloneable {
public String name;
public int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
//因为Object中clone是protected修饰的,故需要重写
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
关于浅度克隆和深度克隆
当一个类中的属性有引用数据类型时,就出现浅度克隆和深度克隆的问题
浅度克隆:克隆是在堆中复制粘贴了一个对象,其中属性的值都与被克隆对象一致。如果该对象的一个属性为引用数据类型,则克隆出来的对象的该属性的值与被克隆对象的该属性的值相同,都是堆中对应对象的地址
深度克隆:对比于浅度克隆,深度克隆就是将对象属性中引用数据类型指向的对象也复制粘贴了一份到克隆出来的对象中,因此克隆对象与被克隆对象的该属性分别指向两个不同的对象的地址,值不相同