📋目录
- 📚引入
- 📚浅拷贝
- 📖定义
- 📖实现方式
- 📖特点
 
- 📚深拷贝
- 📖 定义
- 📖实现方式
- 📖特点
 
- 📚拓展
- 📖Object类
- ✈️toString()方法
- ✈️equals()方法
- ✈️hashcode方法
 
- 📖通过方法实现实参的交换
 
 
 
 
 
 
📚引入
public class Person implements Cloneable{
    public int age;
    public String  name;
    public Person(String name,int age) {
        this.age = age;
        this.name = name;
    }
    @Override
    public String toString() {
        return "Person{" +
                "age=" + age +
                ", name='" + name + '\'' +
                '}';
    }
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}
public class Test1 {
    public static void main(String[] args) throws CloneNotSupportedException{
        Person person1=new Person("zhangsan",10);
        Person person2=(Person)person1.clone();
    }
}
以上代码完善步骤
 
 运行过程分析
 
📚浅拷贝
📖定义
 创建一个新对象,新对象与原对象共享内部的引用对象,但基本数据类型的值是独立的
📖实现方式
示例代码如下
public class Money {
    public double money=9.9;
}
public class Person implements Cloneable{
    public int age;
    public String  name;
    public Money m=new Money();
    public Person(String name,int age) {
        this.age = age;
        this.name = name;
    }
    @Override
    public String toString() {
        return "Person{" +
                "age=" + age +
                ", name='" + name + '\'' +
                '}';
    }
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}
public class Test1 {
    public static void main(String[] args) throws CloneNotSupportedException{
        Person person1=new Person("zhangsan",10);
        Person person2=(Person)person1.clone();
        System.out.println("修改前:"+person1.m.money);
        System.out.println("修改前:"+person2.m.money);
        person2.m.money=99.9;
        System.out.println("修改后:"+person1.m.money);
        System.out.println("修改后:"+person2.m.money);
    }
}
//执行结果
修改前:9.9
修改前:9.9
修改后:99.9
修改后:99.9
运行过程分析
 
📖特点
- 效率相对较高,因为只复制了基本数据类型和引用地址,而不是复制整个引用对象。
- 如果原对象中的引用对象发生变化,浅拷贝得到的新对象中的相应引用对象也会随之改变
📚深拷贝
📖 定义
创建一个新对象,新对象完全独立于原对象,包括内部的所有引用对象也都是独立复制的
📖实现方式
示例代码如下
若要在以上浅拷贝代码的基础上实现深拷贝则需要以下两步:
1.Money类实现Cloneable接口中的clone()方法
2.将Student类中clone()方法中的return super.clone()条件改为
    Person tmp=(Person)super.clone();
    tmp.m=(Money)this.m.clone();
    return tmp;
public class Money implements Cloneable{
    public double money=9.9;
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}
public class Person implements Cloneable{
    public int age;
    public String  name;
    public Money m=new Money();
    public Person(String name,int age) {
        this.age = age;
        this.name = name;
    }
    @Override
    public String toString() {
        return "Person{" +
                "age=" + age +
                ", name='" + name + '\'' +
                '}';
    }
    @Override
    protected Object clone() throws CloneNotSupportedException {
        Person tmp=(Person)super.clone();
        tmp.m=(Money)this.m.clone();
        return tmp;
    }
}
public class Test1 {
    public static void main(String[] args) throws CloneNotSupportedException{
        Person person1=new Person("zhangsan",10);
        Person person2=(Person)person1.clone();
        System.out.println("修改前:"+person1.m.money);
        System.out.println("修改前:"+person2.m.money);
        person2.m.money=99.9;
        System.out.println("修改后:"+person1.m.money);
        System.out.println("修改后:"+person2.m.money);
    }
}
//运行结果
修改前:9.9
修改前:9.9
修改后:9.9
修改后:99.9
运行过程分析
 
📖特点
- 可以确保新对象与原对象完全独立,不会因为原对象的变化而受到影响。
- 实现相对复杂,效率可能比浅拷贝低
📚拓展
📖Object类
Object是Java默认提供的一个类。Java里面除了Object类,所有的类都是存在继承关系的。默认会继承Object父 类。即所有类的对象都可以使用Object的引用进行接收
范例:使用Object接收所有类的对象
class Person{}
class Student{}
public class Test {
    public static void main(String[] args) {
        function(new Person());
        function(new Student());
    }
    public static void function(Object obj) {
        System.out.println(obj);
    }
}
//执行结果:
Person@1b6d3586
Student@4554617c
Object类是参数的最高统一类型。但是Object类也存在有定义好的一些方法。如下:
 
✈️toString()方法
如果要打印对象中的内容,可以直接重写Object类中的toString()方法
// Object类中的toString()方法实现:
public String toString() {
    return getClass().getName() + "@" + Integer.toHexString(hashCode());
    //getClass():获取一个类的字节码对象
    //getClass().getName():获取一个类的全限定名(包名+类名)
    //hashCode():用于计算一个具体的对象位置(内存地址)
    //然后调用Integer.toHexString()方法,将这个地址以16进制输出
}
✈️equals()方法
在Java中,==进行比较时:
a.如果==左右两侧是基本类型变量,比较的是变量中值是否相同
b.如果==左右两侧是引用类型变量,比较的是引用变量地址是否相同
c.如果要比较对象中内容,必须重写Object中的equals方法,因为equals方法默认也是按照地址比较的:
// Object类中的equals方法
public boolean equals(Object obj) {
    return (this == obj);   // 使用引用中的地址直接来进行比较
}
class Person{
 private String name ; 
 private int age ; 
 public Person(String name, int age) {
        this.age = age ; 
        this.name = name ;
 }
public class Test {
 public static void main(String[] args) {
 Person p1 = new Person("lisi", 20) ; 
 Person p2 = new Person("lisi", 20) ; 
        int a = 10;
        int b = 10;
        System.out.println(a == b);             // 输出true
        System.out.println(p1 == p2);           // 输出false
        System.out.println(p1.equals(p2));      // 输出false
 }
}
Person类重写equals方法后,然后比较:
class Person{
    ...
    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false ;
        }
        if(this == obj) {
            return true ;
        }
        // 不是Person类对象
        if (!(obj instanceof Person)) {
            return false ;
        }
 
        Person person = (Person) obj ; // 向下转型,比较属性值
        return this.name.equals(person.name) && this.age==person.age ;
    }
}
结论:比较对象中内容是否相同的时候,一定要重写equals方法
✈️hashcode方法
public String toString() {
    return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
源码中的hashCode()这个方法,用于计算一个具体的对象位置(内存地址),然后调用Integer.toHexString()方法,将这个地址以16进制输出
hashcode方法源码:
public native int hashCode();
该方法是一个native方法,底层是由C/C++代码写的,我们无法看到
一般认为两个名字相同,年龄相同的对象,将存储在同一个位置,在不重写hashcode()方法的情况下,观察以下示例代码的运行结果:
class Person {
    public String name;
    public int age;
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
   }
}
public class TestDemo4 {
    public static void main(String[] args) {
        Person per1 = new Person("lisi", 20) ;
        Person per2 = new Person("lisi", 20) ;
        System.out.println(per1.hashCode());
        System.out.println(per2.hashCode());
   }
}
//执行结果
460141958
1163157884
注意事项:两个对象的hash值不一样
 像重写equals方法一样,我们也可以重写hashcode()方法,代码实现如下:
class Person {
    public String name;
    public int age;
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
   }
 
    @Override
    public int hashCode() {
        return Objects.hash(name, age);
   }
}
public class TestDemo4 {
    public static void main(String[] args) {
        Person per1 = new Person("lisi", 20) ;
        Person per2 = new Person("lisi", 20) ;
        System.out.println(per1.hashCode());
        System.out.println(per2.hashCode());
   }
}
//执行结果
460141958
460141958
注意事项:哈希值一样
 结论:
1、hashcode方法用来确定对象在内存中存储的位置是否相同
2、事实上hashCode()在散列表中才有用,在其它情况下没用。在散列表中hashCode()的作用是获取对象的散列码,进而确定该对象在散列表中的位置
📖通过方法实现实参的交换
public class Test1 {
    public static void swap(int x,int y){
        int tmp=x;
        x=y;
        y=tmp;
    }
    public static void main(String[] args) {
        int a=10;
        int b=20;
        System.out.println("交换前:"+a+" "+b);
        swap(a,b);//调用swap()函数只是交换了x和y的值,并未实现a和b的交换
        System.out.println("交换后:"+a+" "+b);
    }
}
//运行结果
交换前:10 20
交换后:10 20
交换过程
class MyValue{
    public int val;
}
public class Test1 {
    public static void swap(MyValue myV1,
                            MyValue myV2){
        int tem=myV1.val;
        myV1.val=myV2.val;
        myV2.val=tem;
    }
    public static void main(String[] args) {
        MyValue myValue1=new MyValue();
        MyValue myValue2=new MyValue();
        myValue1.val=10;
        myValue2.val=20;
        System.out.println("交换前:"+myValue1.val+" "+myValue2.val);
        swap(myValue1,myValue2);
        System.out.println("交换后:"+myValue1.val+" "+myValue2.val);
    }
}
//运行结果
交换前:10 20
交换后:20 10
交换过程



















