简析Java的浅拷贝和深拷贝

浅拷贝:使用一个已知实例对新创建实例的成员变量逐个赋值。
深拷贝:当一个类的拷贝构造方法,不仅要复制对象的所有非引用成员变量值,还要为引用类型的成员变量创建新的实例,并且初始化为形式参数实例值。

更通俗的描述:浅拷贝只复制一个对象,传递引用,不能复制实例。深拷贝对对象内部的引用均复制,它是创建一个新的实例,并且复制实例。

注意:如果变量都是基本数据类型;浅拷贝跟深拷贝都是一样的。

public class Person {

    private String name;
    private String sex;
    private int age;

    public Person(String name, String sex, int age) {
        this.name = name;
        this.sex = sex;
        this.age = age;
    }

    public Person(Person person){
        this.name = person.name;
        this.sex = person.sex;
        this.age = person.age;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }
}


public class Asian {

    private String skin;
    Person mPerson;

    public Asian(String skin, Person person) {
        this.skin = skin;
        mPerson = person;
    }

    public Asian(Asian asian){
        this(asian.skin,asian.mPerson);
    }

    public static void main(String [] args){
        Person person = new Person("Uart", "men", 23);
        Person person1 = new Person(person);

        System.out.println(person.toString());
        System.out.println(person1.toString());
        System.out.println(person1 == person);

        Asian a1 = new Asian("yellow", new Person("Uart", "men", 23));
        Asian a2 = new Asian(a1);

        System.out.println(a1.toString());
        System.out.println(a2.toString());
        System.out.println(a1 == a2);

        System.out.println(person.getName());
        System.out.println(person1.getName());
        System.out.println(person.getName() == person1.getName());

        person.setName("Jhon");

        //String是不可变对象,在拷贝的时候会被复制
        System.out.println(person.getName());
        System.out.println(person1.getName());
        System.out.println(person.getName() == person1.getName());

    }
}

总结:
1.基本类型
如果变量是基本类型,则拷贝它的值,比如int、float等;
2.对象
如果变量是一个实例对象,则拷贝其地址引用。也就是说新对象与旧对象指向同一个地址引用
3.String字符串
String是不可变对象,在拷贝的时候会被复制。

扩展知识

利用序列化实现对象的拷贝
直接上代码

使用该方法无需继承Cloneable接口实现clone()方法;该工具类的对象只要实现Serializable接口就可以实现对象的克隆。
public static  Object clone(Object object){
        Object cloneObj = null;
        try{
            //写入字节流
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            ObjectOutputStream obs = new ObjectOutputStream(out);
            obs.writeObject(cloneObj);
            obs.close();
                
            //分配内存,写入原始数据,生成新对象
            ByteArrayInputStream ios = new ByteArrayInputStream(out.toByteArray());
            ObjectInputStream ois = new ObjectInputStream(ios);
            cloneObj = (Object) ois.readObject();
            ois.close();
        }catch (Exception e){
            e.printStackTrace();
        }
        return cloneObj;
    }
 
 

补充
浅拷贝例子

//获取真实数据
        GetDateList getDateList = new GetDateList();
        //获取当前年份数据(寿命期与年公用同一份数据)
        year = getDateList.getYear();
        //第一次进来展示最新数据
        month = getDateList.getMonth(year.get(year.size() - 1));
        //第一次进来展示当前天数
        day = getDateList.getDay(year.get(year.size() - 1));

        Log.e("TAG", "year地址值 : " + year + "   month地址值 : " + month + "   day地址值 : " + day);

 /**
     * 获取真实数据
     * @param year
     * @param month
     * @param day
     */
    private void getRealDate(ArrayList year, ArrayList month, ArrayList day) {
        switch (type) {
            case 2 :
            case 3 :
                list = year;
                break;
            case 1 :
                list = month;
                break;
            case 0 :
                list = day;
                break;
        }
    }


 @Override
    public void onCheckedChanged(RadioGroup radioGroup, int checkedId) {
        switch (checkedId) {
            case  R.id.radio_day:
                type = 0;
                list.clear();
                Log.e("TAG   radio_day", "year地址值 : " + year + "   month地址值 : " + month + "   day地址值 : " + day);
                getRealDate(year, month, day);
                adapter.setList(list);
                adapter.setType(type);
                adapter.getClickList().clear();
                adapter.notifyDataSetChanged();
                break;
            case R.id.radio_month:
                type = 1;
                list.clear();
                Log.e("TAG  radio_month", "year地址值 : " + year + "   month地址值 : " + month + "   day地址值 : " + day);
                getRealDate(year, month, day);
                adapter.setList(list);
                adapter.setType(type);
                adapter.getClickList().clear();
                adapter.notifyDataSetChanged();
                break;
            case R.id.radio_year:
                type = 2;
                list.clear();
                Log.e("TAG  radio_year", "year地址值 : " + year + "   month地址值 : " + month + "   day地址值 : " + day);
                getRealDate(year, month, day);
                adapter.setList(list);
                adapter.setType(type);
                adapter.getClickList().clear();
                adapter.notifyDataSetChanged();
                break;
            case R.id.radio_total:
                type = 3;
                list.clear();
                Log.e("TAG   radio_total", "year地址值 : " + year + "   month地址值 : " + month + "   day地址值 : " + day);
                getRealDate(year, month, day);
                adapter.setList(list);
                adapter.setType(type);
                adapter.getClickList().clear();
                adapter.notifyDataSetChanged();
                break;
        }
    }
浅拷贝效果图.PNG

这是因为浅拷贝导致数据clear原始数据也被clear。这里最简单的修改方式是addAll而不采用直接 =来赋值

你可能感兴趣的:(简析Java的浅拷贝和深拷贝)