目录
Object类:
Object类是Java默认提供的一个类,在Java中除了Object类本身之外,它与其他所有类都有继承关系,也就是说它是除本身外所有类的父类~~
使用Object可以接收所有类,也可以用作所有类的返回值:
public static void method(Object o) {//用Object类来接收
System.out.println(o.toString());
}
public static void main(String[] args) {
Dog dog = new Dog("狗狗", 6);
Cat cat = new Cat("猫猫", 5);
method(dog);//传入Dog类
method(cat);//传入Cat类
}
执行结果:
因此在开发中,Object类是最高统一类型,Object定义这么几个方法供我们使用:
在本篇主要讲解equals()、hashCode()、toString()这三个方法~~
equals()方法:
equals()方法可以用来比较两个对象是否相同。如果不重写equals()方法,那么它会直接比较两个类的引用:
这是源码:
其中对于 == 符号,如果是基本类型变量,会比较它们的值是否相等。如果是引用类型变量,比较的就是它们的地址是否相等:
执行结果:
可以证明以上观点~~
那么如果我们需要判断这个类里的值是否相等需要怎么做呢?此时我们要重写equals()方法:
class Dog extends Animal {
public Dog(String name, int age) {
super(name, age);
}
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (obj == this) {
return true;
}
if (!(obj instanceof Dog)) {
return false;
}
Dog dog = (Dog) obj;//向下转型
return this.name.compareTo(dog.name) == 0 && this.age == dog.age;
}
}
public class Main7 {
public static void main(String[] args) {
Dog dog1 = new Dog("狗狗", 6);
Dog dog2 = new Dog("狗狗", 6);
System.out.println(dog1.equals(dog2));
}
}
执行结果:
hashCode()方法:
hashCode()方法可以看作是一个计算地址的方法,它用来确定对象在内存中存储的位置是否相同。
该方法是一个native方法,底层是由C/C++代码写的,因此我们看不到。源码:
我们来看一下两个参数相同的对象的hashCode值:
public static void main(String[] args) {
Dog dog1 = new Dog("狗狗", 6);
Dog dog2 = new Dog("狗狗", 6);
System.out.println(dog1.hashCode());
System.out.println(dog2.hashCode());
}
执行结果:
如果我们认为姓名、年龄相同的两个对象的hashCode值应该是相同的,那么我们可以重写 hashCode()方法:
class Dog extends Animal {
public Dog(String name, int age) {
super(name, age);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
}
public class Main7 {
public static void main(String[] args) {
Dog dog1 = new Dog("狗狗", 6);
Dog dog2 = new Dog("狗狗", 6);
System.out.println(dog1.hashCode());
System.out.println(dog2.hashCode());
}
}
执行结果:
toString()方法:
toString()这个方法可以用来获取对象的信息。如果不重写toString()方法,那么它就会打印类型名+哈希参数:
这是源码:
我们可以重写同String方法来打印:
class Dog extends Animal {
public Dog(String name, int age) {
super(name, age);
}
@Override
public String toString() {//重写toString()类
String str= new String(this.name + this.age + "岁了");
return str;
}
}
public class Main7 {
public static void main(String[] args) {
Dog dog = new Dog("狗狗", 6);
System.out.println(dog.toString());
}
}
执行结果:
Cloneable接口和浅拷贝:
在Object类中有clone()方法,调用这个方法可以创建一个对象的拷贝,但是要重写clone()方法就必须要实现Cloneable接口,否则就会抛CloneNotSupportedException 异常。
class Dog implements Cloneable{
public String name;
public int age;
public Dog(String name, int age) {
this.name = name;
this.age = age;
}
public void show() {
System.out.println("姓名:" + this.name + " 年龄:" + this.age);
}
@Override
public Dog clone() throws CloneNotSupportedException {
return (Dog) super.clone();
}
}
public class Main7 {
public static void main(String[] args) throws CloneNotSupportedException {
Dog dog1 = new Dog("狗狗", 6);
Dog dog2 = dog1.clone();//我们把dog1克隆出来的对象赋给dog2
System.out.println(dog1==dog2);//我们来看一下这两个对象引用变量是否相等
dog1.show();
dog2.show();
dog1.name = "abc";//我们将dog1的name改为abc,看看dog2的name是否会改变
dog1.show();
dog2.show();
}
}
执行结果:
结果显示这两个变量引用并不是同一个,而且改变dog1的值并不会影响dog2的值。那么大家觉得我们这个重写之后的方法是深拷贝还是浅拷贝呢?
答案是浅拷贝!!!!!!!!!
为什么呢???
在回答这个问题之前,我们先理解一下深拷贝与浅拷贝的区别:
浅拷贝:克隆出来的对象的所有变量含有与原来的对象相同的值,而对其他对象的引用都指向原来的对象。也就是说浅拷贝只克隆对象的值,当然也包括引用对象的值,但是它并不会克隆引用对象指向的空间,只会克隆引用对象的值。
深拷贝:而深拷贝要把引用变量所指的对象也要克隆一遍。
一言以盖之就是:浅拷贝只拷贝栈里的内容,而深拷贝既拷贝栈里的内容又拷贝堆里的内容。
回到我们的案例:
因为目前这个Dog类里并不包含引用变量(虽然我们的name是String类,是引用类型,但是在执行name = "abc"的时候,内部会返回一个new String(),所以并不会改变dog2的name的结果),所以看不出来它的拷贝是深拷贝还是浅拷贝,那么我们在Dog类里加上一个引用变量来看看结果吧:
class Weight {
public int weight = 50;
}
class Dog implements Cloneable{
public String name;
public int age;
public Weight W = new Weight();//新增一个引用变量
public Dog(String name, int age) {
this.name = name;
this.age = age;
}
public void show() {
System.out.println("姓名:" + this.name + " 年龄:" + this.age
+ " 体重:" + this.W.weight);
}
@Override
public Dog clone() throws CloneNotSupportedException {
return (Dog) super.clone();
}
}
public class Main7 {
public static void main(String[] args) throws CloneNotSupportedException {
Dog dog1 = new Dog("狗狗", 6);
Dog dog2 = dog1.clone();
System.out.println(dog1==dog2);
dog1.show();
dog2.show();
System.out.println("修改后:");
dog1.name = "abc";
dog1.W.weight = 60;//我们把这个引用变量W的weight修改了
dog1.show();
dog2.show();
}
}
执行结果:
结果如我们预料,由于浅拷贝只拷贝了引用变量的值,因此dog1的W和dog2的W其实指向同一份地址空间,那么我们改变dog1的W也就是改变dog2的W~~
那我们要怎么实现深拷贝呢???
执行结果:dog1的修改并不会影响dog2
如果你不想重写Weight的clone()方法你也可以这样做:
执行结果是一样的~~
OK,那么以上就是本篇的全部内容啦,其实Object类里还有其他方法没和大家细讲,这些都会在以后的文章讲解的哦~~
来点正能量!!