Java对象深拷贝、浅拷贝之枚举类型

枚举在Java中是不可变的,因此不存在深拷贝和浅拷贝的问题。枚举实例在初始化时创建且唯一,直接引用即可。文章通过一个学生类示例展示了深拷贝的实现,说明枚举类型的年级属性在拷贝后不会因原对象的修改而改变。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

问题:为什么属于引用类型的enum不会有深拷贝浅拷贝的问题?

解释:

在Java中,枚举类型是一种特殊的类类型。每个枚举值都是该枚举类型的一个实例,并且这些实例在枚举类型被初始化时就已经被创建。这些实例在程序的整个生命周期中是不可变的。因此,枚举类型的每个值都只存在一个实例。当你引用一个枚举值时,你实际上是引用了这个不可变的实例。这就解释了为什么我们不需要对枚举进行深拷贝或浅拷贝。

深拷贝”和“浅拷贝”是针对可变对象的概念。浅拷贝只复制对象的引用,而不复制对象本身因此原对象和拷贝的对象实际上指向的是同一个对象。深拷贝则是创建一个新对象,并将原对象的所有字段一一复制到新对象中,因此原对象和拷贝的对象是完全独立的。

然而,由于枚举实例是不可变的,所以不存在需要创建新的实例(深拷贝》或者复制实例用(浅拷贝)的情况。你可以直接引用这个实例,而不用担心它会被改变。如果你尝试创建个枚举的新实例或者复制一个枚举实例的引用,你实际上还是会得到指向原来那个实例的引用。这就是为什么我们说在Java中,枚举没有深拷贝和浅拷贝的概念。

举例
测试代码

/**
 * 学生类
 */
 class Student implements Serializable {
    //是否毕业
    private boolean graduate;
    //名字
    private String name;
    //年级-枚举值
    private GradeType gradeType;
    //家庭地址
    private Address address;

    public Student(){};

    public Student(boolean graduate, GradeType gradeType, String name,Address address) {
        this.graduate = graduate;
        if (gradeType == null) {
            this.gradeType = GradeType.G1;
        } else {
            this.gradeType = gradeType;
        }
        this.name = name;
        this.address = address;
    }

    //重写了clone方法来完成Student对象的深拷贝
    @Override
    public Student clone(){
        Student student = new Student();
        student.setGraduate(this.graduate);
        student.setName(this.name);
        student.setGradeType(this.gradeType);
        student.setAddress(this.address);
        return student;
    }

    public boolean isGraduate() {
        return graduate;
    }

    public void setGraduate(boolean graduate) {
        this.graduate = graduate;
    }

    public String getName() {
        return name;
    }

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

    public GradeType getGradeType() {
        return gradeType;
    }

    public void setGradeType(GradeType gradeType) {
        this.gradeType = gradeType;
    }

    public Address getAddress() {
        return address;
    }

    public void setAddress(Address address) {
        this.address = address;
    }
}

/**
 * 年级枚举
 */
 enum  GradeType {
    G1,//高一
    G2,//高二
    G3;//高三
}

/**
 * 地址类
 */
class Address implements Serializable {
    //省
    private String province;
    //市
    private String city;
    //区
    private String district;

    public Address(){};

    public Address(String province, String city, String district) {
        this.province = province;
        this.city = city;
        this.district = district;
    }

    public String getProvince() {
        return province;
    }

    public void setProvince(String province) {
        this.province = province;
    }

    public String getCity() {
        return city;
    }

    public void setCity(String city) {
        this.city = city;
    }

    public String getDistrict() {
        return district;
    }

    public void setDistrict(String district) {
        this.district = district;
    }
}

测试方法

	    public static void main(String[] args) {
        Address a1 = new Address("广东省","广州市","天河区");
        Student s1 = new Student(Boolean.FALSE,GradeType.G1,"zhangsan",a1);
        Student s2 = s1.clone();
        System.out.println("s1="+ JSONObject.toJSONString(s1));
        System.out.println("s2="+JSONObject.toJSONString(s2));
        System.out.println("-----------做修改---------");
        //将拷贝的学生2名称改成zhangsanfeng
        s2.setName("zhagnsanfeng");
        //将拷贝的学生2的年级改成G3
        s2.setGradeType(GradeType.G3);
        //将毕业状态改成已毕业
        s2.setGraduate(Boolean.TRUE);
        //将拷贝的学生2的地址改成白云区
        Address a2 = s2.getAddress();
        a2.setDistrict("白云区");
        System.out.println("s1="+JSONObject.toJSONString(s1));
        System.out.println("s2="+JSONObject.toJSONString(s2));
    }

结果
在这里插入图片描述
可以看到在修改之前,打印出来的学生s1和学生s2有着相同的人员信息,
在修改学生s2的名字、年级、毕业状态和家庭住址后,可以发现只有家庭住址的改变影响到了学生s1,修改学生s2后,学生s1的地址也从天河区变成了白云区,而同为引用类型的年级并没有因为s2的修改而改变。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值