类与对象的拓展知识(Cloneable接口和浅拷贝、Object类、toString()、equals()、hashcode()) --- Java内功心法

目录

Object类:

equals()方法:

hashCode()方法:

toString()方法:

Cloneable接口和浅拷贝:


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类里还有其他方法没和大家细讲,这些都会在以后的文章讲解的哦~~

来点正能量!!

“春蚕到死丝方尽 蜡炬成灰泪始干”_哔哩哔哩_bilibili

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值