equals(object obj)方法 :
equals(object obj) 的含义
- 默认的equals方法比较两个对象的引用的地址是否相等,不是比较具体的值,如要比较两个对象中的值/内容是否相等,此时要重写equals( )方法。
- 然而,许多Java类(如String、Integer等)已经重写了equals( )方法,此时的equals( )比较的是两个对象的。
- 在Java中,对象的引用是一个地址值,该地址指向该对象在内存中的位置。通过引用,我们可以访问和操作该对象。
equals(object obj) 源码
public boolean equals(Object obj) {
return (this == obj);
}
equals(object obj) 例子
public class Test() {
//在普通的对象中时,equals()方法比较的是对象的引用(比较对象间的地址值)是否相等
static class Student1 {
String name = "张三";
int age = 18;
}
static class Student2 {
String name = "张三";
int age = 18;
}
static class Student3 {
String name = "李四";
}
public static void main(String[] args) {
Object str1 = "Hello World";
Object str2 = "Hello World2";
Object str3 = str1;
Object str4 = "Hello World";
// 在String、Integer等时,equals()方法已被重写,此时比较的是对象的内容
System.out.println(str1.equals(str2)); //false
System.out.println(str1.equals(str3)); //true
System.out.println(str1.equals(str4)); //true
System.out.println("----------------------------");
Student1 s1 = new Student1();
Student2 s2 = new Student2();
Student3 s3 = new Student3();
//比较的是两个对象的引用(可理解为: 地址值),就算值相等,地址值一般也不会相等的
System.out.println(s1.equals(s2)); // false
System.out.println(s1.equals(s3)); //false
//要判断对象的内容是否相等,要重写equals()方法
}
}
重写equals(object obj)方法
重写equals( )方法:判断对象的内容
public class Student {
//重写equals()方法,通过该方法来判断两个对象的内容是否相等
private String name;
private int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public boolean equals(Object obj) {
//传入一个要判断的对象
if (this == obj) {
//如果两个对象引用相等,表明是同一个对象,对象的内容自然也相等
return true;
}
//如果obj为null 或 两个对象的类都不同,那么对象的内容自然也是不相同
if (obj == null || getClass() != obj.getClass()) {
return false;
}
//将obj对象进行类型转换,然后进行对象的内容的判断
Student student = (Student) obj;
return age == student.age && Objects.equals(name, student.name); //Objects.equals()比较的是对象的内容
}
public static void main(String[] args) {
Student student1 = new Student("张三",18);
Student student2 = new Student("张三",20);
Student student3 = new Student("张三",18);
//如果用默认的equals()方法判断,那么这三个对象都不相等,重写后则 student1与 student3相等
System.out.println(student1.equals(student2)); //false
System.out.println(student1.equals(student3)); //true
}
}
hashCode()方法 :
hashCode()的含义
- 默认的hashCode()方法用于为对象生成一个整数表示的哈希码。
- 对象的哈希码是通过哈希函数计算得出的。哈希函数通过会考虑对象的内部状态和内容,以便为不同的对象生成不同的哈希码。
- 当我们需要使用哈希表数据结构(如HashMap、HashSet)等时。哈希表使用对象的哈希码来确定存储和查找的位置,通过合理的哈希码分布可以提高查找效率。
- 需要注意的是,不同的对象可能会返回相同的哈希值,这被称为哈希冲突。
- 在Java中,如果你重写了
equals()
方法,那么你也应该重写hashCode()
方法,以保持它们的一致性。这是因为Java的规范要求相等的对象必须有相等的哈希值。
hashCode() 源码
public native int hashCode();
hashCode() 例子
public class Test {
public static class Student1 {
}
public static class Student2 {
}
public static void main(String[] args) {
Student student = new Student();
Student2 student2 = new Student2();
//两个不通过的对象的哈希码是不一样的
System.out.println(student.hashCode()); //668386784
System.out.println(student2.hashCode()); //668386784
//
System.out.println(student.hashCode()==student2.hashCode()); // faslse
}
}
为什么重写了equals()方法也要重写hashCode()方法呢?
- 如果你重写了equals( )方法,那么你也应该重写``方法,以保持它们的一致性。这是因为Java的规范要求相等的对象必须有相等的哈希值。
- 如果两个对象根据equals( )方法是相等的,那么它们的哈希码(由hashCode( )方法返回)应该相同。这是因为哈希码通常被用于在哈希表等数据结构中快速查找对象。如果相等的对象返回了不同的哈希码,那么可能会导致错误的行为
重写hashCode()方法
public class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
//此处应重写equals()方法,但为节省代码量就不写了....,可看重写equals()篇
@Override //根据对象的属性值计算出一个哈希码,以确保相等的对象具有相等的哈希码。
public int hashCode() {
// 定义一个常量prime,它是一个质数(通常选择一个质数可以保持哈希码的均匀分布)
final int prime = 31;
int result = 1; //result变量存储最终的哈希码
result = prime * result + age;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
public static void main(String[] args) {
Person person1 = new Person("张三", 20);
Person person2 = new Person("张三", 20);
//上面两个对象如果重写了equals()方法,那返回值是true,此时也要重写hashCode()方法以确保两个对象的哈希码是一样的
System.out.println(person1.hashCode()); // 776470
//两个对象的哈希码是一样的,这是重写了hashCode的功劳,也符合Java规则,因为重写了equals方法后对象一样,哈希码也要一样
System.out.println(person2.hashCode()); //776470
}
}
getClass()方法 :
getClass()的含义
- getClass()用于返回对象的运行时类。
- getClass()返回值是一个Class对象,可以使用该对象调用各种方法来获取有关类的信息。
getClass() 源码
@HotSpotIntrinsicCandidate
public final native Class<?> getClass();
getClass() 例子
public class Test {
public static class MyClass {
private int value;
public MyClass(int value) {
this.value = value;
}
//输出信息的方法
public void printInfo() {
System.out.println(value);
}
}
public static void main(String[] args) throws
NoSuchFieldException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
MyClass myClass1 = new MyClass(10);
MyClass myClass2 = new MyClass(20);
//获得类对应的Class类
//使用 getClass()获得运行中的MyClass (获得Class类)
Class<?> class1 = myClass1.getClass();
Class<?> class2 = myClass2.getClass();
//获得类名
System.out.println(class1.getName()); // Test$MyClass
System.out.println(class2.getName()); // Test$MyClass
//获得方法对应的Method类
Method printInfo_myClass1 = class1.getMethod("printInfo"); //返回一个Method类
Method printInfo_myClass2 = class2.getMethod("printInfo");
//调用类中方法
// invoke()方法是Method类提供的一个方法,调用该类中的方法
printInfo_myClass1.invoke(myClass1); //方法输出: 10
printInfo_myClass2.invoke(myClass2); //方法输出: 20
}
}
toString()方法 :
toString()的含义
- 默认的toString( )方法用于将对象转换为字符串形式。
- 在Java中,如果一个类没有重写toString()方法,那么该类的toString()方法将返回该类的类名和哈希码的十六进制字符串表示形式。如果我们想打印对象时返回的该对象中的内容,此时我们就需要重写toString( )方法。
- 我们可以根据对象的属性值和需求来自定义的字符串的表示形式。
- 例如,对于一个
Person
类,我们可以重写toString()
方法来返回包含对象属性的字符串表示形式,如姓名和年龄。
toString() 源码
- getClass().getName() : 获得运行时类的类名
- Integer.toHexString : 用于将整数转换为十六进制的字符串
- hashCode() : 为对象生成一个整数哈希码
- Integer.toHexString(hashCode()); :哈希码的十六进制字符串表示形式
- return getClass().getName() + “@” + Integer.toHexString(hashCode()); :
返回一个包含对象类名和哈希码的十六进制字符串表示形式
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
toString() 例子
public class Person {
public static void main(String[] args) {
Person person = new Person();
//输出的默认的toString()方法的内容: 类名+@+哈希码的十六进制字符串表现形式
System.out.println(person); //Person@16b98e56
}
重写toString()方法
public class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
public static void main(String[] args) {
Person person = new Person("王五",21);
System.out.println(person); // 打印的是: Person{name='王五', age=21}
//如果不用重写toString方法,那打印的就是 类名+@+哈希码的十六进制字符串表示形式
}
}
clone() 方法:
clone()的含义
- clone( ): 创建并返回此对象的副本。
- 要使用clone( )方法,它需要目标类必须实现cloneable接口。
- 默认的clone()是浅拷贝,即复制对象时,新对象和原对象共享相同的内部对象引用。这意味着,对于引用类型的属性,副本和原对象将引用相同的对象实例。
clone() 源码
protected native Object clone() throws CloneNotSupportedException;
clone() 例子
public class MyClass implements Cloneable {
private int id;
private String name;
public MyClass(int id, String name) {
this.id = id;
this.name = name;
}
@Override
public String toString() {
return "MyClass{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
public static void main(String[] args) throws CloneNotSupportedException {
MyClass class1 = new MyClass(1, "张三");
MyClass class2 = (MyClass) class1.clone();
System.out.println(class1); // MyClass{id=1, name='张三'}
System.out.println(class2); // MyClass{id=1, name='张三'}
}
}