概述:所有类的根类(父类),所有的类都会直接或者间接继承Object类
Object中的toString()方法:
如果不重写这个toString方法:默认形式是:
return getClass().getName() + "@" + Integer.toHexString(hashCode());
这个我们可以进到Object里面去看
a.如果没有重写Object中的toString方法,直接输出对象名会默认调用Object中的toString方法,直接输出地址值
这两行代码生成的结果是一样的
b.如果重写了Object中的toString方法,再输出地址值,重写没有意义,所以重写完toString之后,应该返回对象的内容
然后我们按住ctrl 鼠标点击list的toString方法追踪一下
可以得出这里重写了这个toString()方法。
对这个JavaBean对象重写toString方法之后也是一样
Object的equals方法:
这部分的介绍我直接通过代码的案例来讲:
第一个案例:
class A {
String name;
int age;
@Override
public String toString() {
return "A{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
public class Test {
public static void main(String[] args) {
A a1 = new A();
A a2 = new A();
System.out.println(a1==a2);
System.out.println(a1.equals(a2));
}
}
第一段代码:我创建了一个A对象,我并没有重写equals方法,所以我们也可以知道,如果我在主函数中调用,那应该调用Object的默认equals方法
输出结果:
false
false
这是应该Object的默认equals方法比较得是地址值
第二个案例:
public class Test {
public static void main(String[] args) {
A a1 = new A();
A a2 = new A();
System.out.println(a1==a2);
System.out.println(a1.equals(a2));
System.out.println("========================");
String a = "abc";
String b = "abc";
System.out.println(a==b);
System.out.println(a.equals(b));
}
}
class A {
String name;
int age;
@Override
public String toString() {
return "A{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
这一段代码我又创建了两个String变量:值都是"abc"
输出结果:
true
true
a==b 最后能输出true的原因是:
在Java中,当你声明两个字符串变量 a
和 b
并初始化为相同的值 "abc"
时,System.out.println(a==b)
会输出 true
。这是因为在Java中,字符串常量池(String Pool)的概念起了作用。
字符串常量池是一个特殊的内存区域,用于存储所有创建的字符串实例。当你创建一个新字符串 "abc"
时,实际上系统会在字符串常量池中查找是否有相同内容的字符串,如果找到了,就直接引用那个已经在池中的对象,而不是新建一个新的对象。所以,"abc"
和 "abc"
实际上指向的是同一个内存地址,因此 ==
运算符比较它们的时候返回 true
,表示它们是相等的。
a.equals(b)最后能输出true的原因是:String重写了equals方法,在重写的方法中比较了两个字符串的序列
所以我们可以先做一个小总结:
a.如果没有重写Object中的equals方法,那么就会调用Object中的equals方法,比较对象的地址值
b.如果重写了Object中的equals方法,那么就会调用重写后的equals方法,应该比较对象的内容
接着我们再从idea自动给我们重写的equals方法的几行代码中分析一下逻辑:
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
A a = (A) o;
return age == a.age && Objects.equals(name, a.name);
}
这一段是编辑器自动帮我们写的equals方法
首先先说明一下,这里面的this是什么,在Java面向对象的特性中有一个this
这里的this是指当前对象,也就是调用这个方法的对象:
比如:a.equals(b),那这里的a就是当前对象,也就是这个this,b就是Object o 的o
this == o 这个的作用是判断如果比较的对象和当前对象一致的话,就不需要再比了,直接返回true
o == null 这个的作用是判断传入的对象是否为空,为空直接短路后面的判断,直接返回false
getClass() != o.getClass()这个就比较复制,需要展开来说了
看这一段代码,我试图去将A的属性中的age和name和当前对象进行比较,结果发现直接爆红
这是为什么?
因为age和name是子类(这里的子类相对的父类就是Object),父类不能调用子类私有属性
OK,写道这里肯定会有人说,向下转型就行了。
结果肯定是可以的
不过我们再来看:
如果我们在外面传了一个list集合,那这样还能判断出来嘛
答案肯定是不能,应该是会报转换类型错误的报错java.lang.ClassCastException
解决办法是什么呢?
就是在向下转型的时候用instanceof关键字判断一下。
所以等我们把上面这些判断都明白了,自然就明白了代码自动给我们生成的getClass() != o.getClass()这段代码。
最后,我们再来说一下 "==" 和 equals的区别
在Java中,==
和.equals()
是两个用于比较的对象运算符,但它们在用途和用法上有所不同:
-
==
运算符:- 用于比较基本数据类型(如int、char等)或引用类型的变量是否指向同一内存地址。
- 当比较对象时,它检查的是两个对象的引用是否完全相同,即它们在内存中的位置是否一样。
- 对于字符串和数组,如果两个对象的引用相等,则
==
返回true,即使它们的内容相同。
-
.equals()
方法:- 这是一个方法,通常由Object类定义,并在所有类中继承,包括String、Integer等引用类型。
- 对于自定义类的对象,
.equals()
方法可以根据类的设计意图来判断两个对象的内容是否相等。 - 在String类中,
.equals()
默认比较的是字符串的实际内容;而在其他可变类型如ArrayList,通常重写为比较元素内容而非引用。
总结来说,==
主要用于直接比较对象的地址,而.equals()
则是用来比较对象的内容是否相等。如果你想要比较两个对象的数据值而不是它们的引用,应该使用.equals()
,除非你知道你在比较的是不可变类型(比如基本类型或String),在这种情况下,==
就足够了。