Java创建对象的5种方式以及浅克隆与深克隆的区别

Java创建对象的5种方式

哔哩哔哩链接:https://www.bilibili.com/video/BV1Bu411U7Ya?spm_id_from=333.999.0.0&vd_source=7c5f1f4c039688f19024d50ef51aaed1

1.Student类

static class Student implements Serializable, Cloneable {
        private String id;

        private String name;

        private Integer age;

        public Student() {
        }

        public Student(String id, String name, Integer age) {
            this.id = id;
            this.name = name;
            this.age = age;
        }

        public String getId() {
            return id;
        }

        public void setId(String id) {
            this.id = id;
        }

        public String getName() {
            return name;
        }

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

        public Integer getAge() {
            return age;
        }

        public void setAge(Integer age) {
            this.age = age;
        }

        @Override
        public String toString() {
            return "Student{" +
                    "id='" + id + '\'' +
                    ", name='" + name + '\'' +
                    ", age=" + age +
                    '}';
        }

        @Override
        protected Object clone() throws CloneNotSupportedException {
            return super.clone();
        }
    }

2.java创建对象的5种方式

// java创建对象的5种方式
@Test
public void createObject() {
    System.out.println(createStudent01());
    System.out.println(createStudent02());
    System.out.println(createStudent03());
    System.out.println(createStudent04());
    System.out.println(createStudent05());
}


// 1.通过new xxx()调用构造方法创建对象
private Student createStudent01() {
    return new Student(UUID.randomUUID().toString(), "zhangsan", 20);
}

// 2.通过反射,调用xxx.getClass().newInstance()创建对象
private Student createStudent02() {
    try {
        // 得到一个空的对象
        Student student = Student.class.newInstance();
        student.setId(UUID.randomUUID().toString());
        student.setName("lisi");
        student.setAge(22);
        return student;
    } catch (InstantiationException e) {
        e.printStackTrace();
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    }
    return null;
}

// 3.通过反射,调用construct.newInstance()创建对象
private Student createStudent03() {
    // 获取Student类对应的class字节码对象
    Class<Student> studentClass = Student.class;
    Constructor<Student> constructor = null;
    try {
        // 获取Student类中有参构造方法
        constructor = studentClass.getConstructor(String.class, String.class, Integer.class);
    } catch (NoSuchMethodException e) {
        e.printStackTrace();
    }

    Student wanwu = null;
    try {
        // 创建对象
        wanwu = constructor.newInstance(UUID.randomUUID().toString(), "wanwu", 25);
    } catch (InstantiationException e) {
        e.printStackTrace();
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    } catch (InvocationTargetException e) {
        e.printStackTrace();
    }
    return wanwu;
}

// 4.通过xxx.clone()克隆方式创建(需要实现Cloneable接口,重写clone方法)
public Student createStudent04(){
    Student student = new Student(UUID.randomUUID().toString(), "zhaoliu", 26);
    try {
        Student clone = (Student)student.clone();
        return clone;
    } catch (CloneNotSupportedException e) {
        e.printStackTrace();
    }
    return null;
}

// 5.通过序列化,反序列化创建对象(需要实现Serializable接口)
public Student createStudent05(){
    Student student = new Student(UUID.randomUUID().toString(), "tianqi", 27);
    try {
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("E:\\student.txt"));
        ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("E:\\student.txt"));
        // 调用输出流将student对象序列化到E:\student.txt
        objectOutputStream.writeObject(student);
        // 从E:\student.txt文件中反序列化出student对象
        Student object = (Student)objectInputStream.readObject();
        return object;
    } catch (IOException e) {
        e.printStackTrace();
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    }
    return null;
}

在这里插入图片描述

3.浅克隆与深克隆

哔哩哔哩链接:https://www.bilibili.com/video/BV1Sa41127pU?spm_id_from=333.999.0.0&vd_source=7c5f1f4c039688f19024d50ef51aaed1
在这里插入图片描述
在这里插入图片描述

3.1.浅克隆

Teacher
package com.bilibili.juc.clone;

public class Teacher {

    private Integer pkid;

    private String name;

    public Teacher() {
    }

    public Teacher(Integer pkid, String name) {
        this.pkid = pkid;
        this.name = name;
    }

    public Integer getPkid() {
        return pkid;
    }

    public void setPkid(Integer pkid) {
        this.pkid = pkid;
    }

    public String getName() {
        return name;
    }

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

    @Override
    public String toString() {
        return "Teacher{" +
                "pkid=" + pkid +
                ", name='" + name + '\'' +
                '}';
    }
}

Student
package com.bilibili.juc.clone;


public class Student implements Cloneable{

    private double weight;

    private Integer pkid;

    private String name;

    // 持有一个教师对象的引用
    private Teacher teacher;

    public Student(double weight, Integer pkid, String name, Teacher teacher) {
        this.weight = weight;
        this.pkid = pkid;
        this.name = name;
        this.teacher = teacher;
    }

    public double getWeight() {
        return weight;
    }

    public void setWeight(double weight) {
        this.weight = weight;
    }

    public Integer getPkid() {
        return pkid;
    }

    public void setPkid(Integer pkid) {
        this.pkid = pkid;
    }

    public String getName() {
        return name;
    }

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

    public Teacher getTeacher() {
        return teacher;
    }

    public void setTeacher(Teacher teacher) {
        this.teacher = teacher;
    }

    @Override
    public String toString() {
        return "Student{" +
                "weight=" + weight +
                ", pkid=" + pkid +
                ", name='" + name + '\'' +
                ", teacher=" + teacher +
                '}';
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

浅克隆测试
// 浅拷贝演示
@org.junit.jupiter.api.Test
public void qianTest() throws CloneNotSupportedException {
    Teacher teacher = new Teacher(1, "黄老师");
    // 浅拷贝之前的对象
    Student student = new Student(50.00, 1, "张三", teacher);
    // 浅拷贝之后的对象
    Student student1 = (Student) student.clone();

    System.out.println(student == student1);
    System.out.println(student.getTeacher() == student1.getTeacher());
    System.out.println("浅拷贝前teacher的hashcode:" + student.getTeacher().hashCode());
    System.out.println("浅拷贝后teacher新对象的hashcode:" + student1.getTeacher().hashCode());

    System.out.println("克隆之前student学生的老师:" + student.getTeacher().getName());
    // 将克隆后的对象student1的老师姓名改为张老师,导致旧student的老师姓名也被修改
    student1.getTeacher().setName("张老师");
    System.out.println("克隆之前的student学生:" + student);
    System.out.println("克隆之后的student1学生:" + student1);
}

在这里插入图片描述

3.2.深克隆

Teacher2
package com.bilibili.juc.clone;

public class Teacher2 implements Cloneable{

    private Integer pkid;

    private String name;

    public Teacher2() {
    }

    public Teacher2(Integer pkid, String name) {
        this.pkid = pkid;
        this.name = name;
    }

    public Integer getPkid() {
        return pkid;
    }

    public void setPkid(Integer pkid) {
        this.pkid = pkid;
    }

    public String getName() {
        return name;
    }

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

    @Override
    public String toString() {
        return "Teacher{" +
                "pkid=" + pkid +
                ", name='" + name + '\'' +
                '}';
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

Student2
package com.bilibili.juc.clone;

public class Student2 implements Cloneable{

    private double weight;

    private Integer pkid;

    private String name;

    // 持有一个教师对象的引用
    private Teacher2 teacher;

    public Student2(double weight, Integer pkid, String name, Teacher2 teacher) {
        this.weight = weight;
        this.pkid = pkid;
        this.name = name;
        this.teacher = teacher;
    }

    public double getWeight() {
        return weight;
    }

    public void setWeight(double weight) {
        this.weight = weight;
    }

    public Integer getPkid() {
        return pkid;
    }

    public void setPkid(Integer pkid) {
        this.pkid = pkid;
    }

    public String getName() {
        return name;
    }

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

    public Teacher2 getTeacher() {
        return teacher;
    }

    public void setTeacher(Teacher2 teacher) {
        this.teacher = teacher;
    }

    @Override
    public String toString() {
        return "Student{" +
                "weight=" + weight +
                ", pkid=" + pkid +
                ", name='" + name + '\'' +
                ", teacher=" + teacher +
                '}';
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        Student2 student = null;
        student = (Student2) super.clone();
        // 拷贝teacher对象
        student.teacher = (Teacher2)this.teacher.clone();
        return student;
    }
}

深克隆测试
// 深拷贝演示
@org.junit.jupiter.api.Test
public void shenTest() throws CloneNotSupportedException {
    Teacher2 teacher = new Teacher2(1, "黄老师");
    // 深拷贝之前的对象
    Student2 student = new Student2(50.00, 1, "张三", teacher);
    // 深拷贝之后的对象
    Student2 student1 = (Student2) student.clone();

    System.out.println(student == student1);
    System.out.println(student.getTeacher() == student1.getTeacher());
    System.out.println("深拷贝前teacher的hashcode:" + student.getTeacher().hashCode());
    System.out.println("深拷贝后teacher新对象的hashcode:" + student1.getTeacher().hashCode());

    System.out.println("克隆之前student学生的老师:" + student.getTeacher().getName());
    // 将克隆后的对象student1的老师姓名改为张老师,因为是深拷贝,旧student的老师姓名不会被修改
    student1.getTeacher().setName("张老师");
    System.out.println("克隆之前的student学生:" + student);
    System.out.println("克隆之后的student1学生:" + student1);
}

在这里插入图片描述

3.3.通过序列化实现深克隆

Teacher3
package com.bilibili.juc.clone;

import java.io.Serializable;

public class Teacher3 implements Serializable {

    private Integer pkid;

    private String name;

    public Teacher3() {
    }

    public Teacher3(Integer pkid, String name) {
        this.pkid = pkid;
        this.name = name;
    }

    public Integer getPkid() {
        return pkid;
    }

    public void setPkid(Integer pkid) {
        this.pkid = pkid;
    }

    public String getName() {
        return name;
    }

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

    @Override
    public String toString() {
        return "Teacher{" +
                "pkid=" + pkid +
                ", name='" + name + '\'' +
                '}';
    }
}
Student3
package com.bilibili.juc.clone;

import java.io.*;

public class Student3 implements Serializable {

    private double weight;

    private Integer pkid;

    private String name;

    // 持有一个教师对象的引用
    private Teacher3 teacher;

    public Student3(double weight, Integer pkid, String name, Teacher3 teacher) {
        this.weight = weight;
        this.pkid = pkid;
        this.name = name;
        this.teacher = teacher;
    }

    public double getWeight() {
        return weight;
    }

    public void setWeight(double weight) {
        this.weight = weight;
    }

    public Integer getPkid() {
        return pkid;
    }

    public void setPkid(Integer pkid) {
        this.pkid = pkid;
    }

    public String getName() {
        return name;
    }

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

    public Teacher3 getTeacher() {
        return teacher;
    }

    public void setTeacher(Teacher3 teacher) {
        this.teacher = teacher;
    }

    @Override
    public String toString() {
        return "Student{" +
                "weight=" + weight +
                ", pkid=" + pkid +
                ", name='" + name + '\'' +
                ", teacher=" + teacher +
                '}';
    }


    // 通过序列化实现深拷贝
    public Student3 deepCloneBySerializable() {
        Student3 student = null;
        ByteArrayOutputStream byteArrayOutputStream = null;
        ObjectOutputStream objectOutputStream = null;
        ByteArrayInputStream byteArrayInputStream = null;
        ObjectInputStream objectInputStream = null;
        try {
            byteArrayOutputStream = new ByteArrayOutputStream();
            objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);//对象序列化
            objectOutputStream.writeObject(this);
            byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
            objectInputStream = new ObjectInputStream(byteArrayInputStream);
            //对象的反序列化
            student = (Student3) objectInputStream.readObject();
            return student;
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        } finally {
            if (null != objectInputStream) {
                try {
                    objectInputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (null != byteArrayInputStream) {
                try {
                    byteArrayInputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (null != objectOutputStream) {
                try {
                    objectOutputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (null != byteArrayOutputStream) {
                try {
                    byteArrayOutputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return null;
    }
}
通过序列化实现深克隆测试
@org.junit.jupiter.api.Test
public void searilizableTest() throws CloneNotSupportedException {
    Teacher3 teacher = new Teacher3(1, "黄老师");
    // 深拷贝之前的对象
    Student3 student = new Student3(50.00, 1, "张三", teacher);
    // 深拷贝之后的对象
    Student3 student1 = (Student3) student.deepCloneBySerializable();

    System.out.println(student == student1);
    System.out.println(student.getTeacher() == student1.getTeacher());
    System.out.println("深拷贝前teacher的hashcode:" + student.getTeacher().hashCode());
    System.out.println("深拷贝后teacher新对象的hashcode:" + student1.getTeacher().hashCode());

    System.out.println("克隆之前student学生的老师:" + student.getTeacher().getName());
    // 将克隆后的对象student1的老师姓名改为张老师,因为是深拷贝,旧student的老师姓名不会被修改
    student1.getTeacher().setName("张老师");
    System.out.println("克隆之前的student学生:" + student);
    System.out.println("克隆之后的student1学生:" + student1);
}
    

在这里插入图片描述

3.4 不实现深克隆

Attachment:

package com.bilibili.juc.sheng;

import java.io.Serializable;

public class Attachment  implements Serializable {

    private String name;

    public String getName() {
        return name;
    }

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

YuelyLog :

package com.bilibili.juc.sheng;

import java.io.Serializable;

public class YuelyLog implements Serializable,Cloneable {
    private Attachment attachment;
    private String name;
    private String date;

    @Override
    protected YuelyLog clone() throws CloneNotSupportedException {
        return (YuelyLog)super.clone();
    }

    public Attachment getAttachment() {
        return attachment;
    }

    public void setAttachment(Attachment attachment) {
        this.attachment = attachment;
    }

    public String getName() {
        return name;
    }

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

    public String getDate() {
        return date;
    }

    public void setDate(String date) {
        this.date = date;
    }
}

ShengTest :

package com.bilibili.juc.sheng;

import java.io.IOException;
import java.util.Date;

public class ShengTest {

    public static void main(String[] args) throws IOException, ClassNotFoundException, CloneNotSupportedException {
        Attachment attachment = new Attachment();
        attachment.setName("wj");
        YuelyLog yuelyLog = new YuelyLog();
        yuelyLog.setAttachment(attachment);
        yuelyLog.setDate(new Date().toString());
        yuelyLog.setName("dn");
        System.out.println("yelyLog:name="+(yuelyLog.getAttachment().getName()));

        YuelyLog clone = yuelyLog.clone();
        clone.getAttachment().setName("clone");
        System.out.println("yelyLog:name="+(yuelyLog.getAttachment().getName()));
    }
}

输出结果:
yelyLog:name=wj
yelyLog:name=clone

说明在修改浅拷贝队形的同时原对象也发生了变化,这是一种非常危险的事情,如果处理不当,对全局性的变量或者原对象进项操作会引起大bug

其实我们拷贝一个对象就是希望他是独立的,可操作的,不会因为修改他而引起原对象发生变化。

通过序列化实现深拷贝

public class YuelyLog implements Serializable,Cloneable {
    private Attachment attachment;
    private String name;
    private String date;

    @Override
    protected YuelyLog clone() throws CloneNotSupportedException {
        return (YuelyLog)super.clone();
    }

    public Attachment getAttachment() {
        return attachment;
    }

    public void setAttachment(Attachment attachment) {
        this.attachment = attachment;
    }

    public String getName() {
        return name;
    }

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

    public String getDate() {
        return date;
    }

    public void setDate(String date) {
        this.date = date;
    }

    /**
     * 使用序列化技术实现深拷贝
     * @return
     */
    public YuelyLog deepClone() throws IOException,ClassNotFoundException{
        //将对象写入流中
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(outputStream);
        objectOutputStream.writeObject(this);
        //从流中取出
        ByteArrayInputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray());
        ObjectInputStream objectInputStream = new ObjectInputStream(inputStream);
        return (YuelyLog)objectInputStream.readObject();

    }
}

之后将YuelyLog clone = yuelyLog.clone();改为YuelyLog clone = yuelyLog.deepClone();
代码如下:

package com.bilibili.juc.sheng;

import java.io.IOException;
import java.util.Date;

public class ShengTest {

    public static void main(String[] args) throws IOException, ClassNotFoundException, CloneNotSupportedException {
        Attachment attachment = new Attachment();
        attachment.setName("wj");
        YuelyLog yuelyLog = new YuelyLog();
        yuelyLog.setAttachment(attachment);
        yuelyLog.setDate(new Date().toString());
        yuelyLog.setName("dn");
        System.out.println("yelyLog:name="+(yuelyLog.getAttachment().getName()));

        YuelyLog clone = yuelyLog.deepClone();
        clone.getAttachment().setName("clone");
        System.out.println("yelyLog:name="+(yuelyLog.getAttachment().getName()));
    }
}

输出结果:
yelyLog:name=wj
yelyLog:name=wj

在这里强调一点,当然如果你能保证在拷贝对象后,你只是对拷贝对象成员变量为基本类型和String类型进行操作,可以使用浅拷贝,像对复杂对象操作,我们一般使用深拷贝,或者对非基本类型单独实现拷贝进行修改。业务中灵活掌握。

4.方法重载和重写的区别

哔哩哔哩链接:https://www.bilibili.com/video/BV1sS4y1j7tX?spm_id_from=333.999.0.0&vd_source=7c5f1f4c039688f19024d50ef51aaed1

在这里插入图片描述
在这里插入图片描述

5.String s = new String(“abc”)创建了几个对象

在这里插入图片描述

在这里插入图片描述

public class NewString {
    public static void main(String[] args) {
        // 在方法执行过程中,根据字节码指令,往栈里写入数据或提取数据,即入栈/出栈。某些字节码指令把值压入操作数栈,其余指令将操作数取出栈。
        // 1.在字符串常量池中创建了一个“abc”的字符串常量
        // 2.把字符串常量“abc”的值压入到操作数栈中
        // 3.把栈中的元素存入到局部变量表索引为1的位置
        // 4.方法返回
        String abc = "abc";
    }
}

在这里插入图片描述

public class NewString {
    public static void main(String[] args) {
        // 1.创建一个新的实例
        // 2.复制栈中的元素并把复制的值压入到操作数栈中
        // 3.在字符串常量池中创建了一个“abc”的字符串常量
        // 4.把字符串常量“abc”的值压入到操作数栈中
        // 5.调用String构造方法,
        // 6.把栈中的元素存入到局部变量表索引为1的位置
        // 7.方法返回
        String abc = new String("abc");
    }
}

在这里插入图片描述

public class NewString {
    public static void main(String[] args) {

        // 1.在字符串常量池中创建了一个“abc”的字符串常量
        // 2.把栈中的元素存入到局部变量表索引为1的位置
        // 3.创建一个新的实例
        // 4.复制栈中的元素并把复制的值压入到操作数栈中
        // 5.由于之前已经创建了“abc”字符串常量池,即“abc”已经在字符串常量池中存在,直接获取#2(abc在字符串常量池中)的地址
        // 6.调用String构造方法
        // 7.把栈中的元素存入到局部变量表索引为2的位置
        // 8.方法返回
        String ABC = "abc";
        String abc = new String("abc");
    }
}

在这里插入图片描述

喜欢请关注我

至此,我们的Java创建对象的5种方式以及浅克隆与深克隆的区别就讲解完成了。喜欢我的话可以关注我的微信公众号我爱学习呀嘻嘻 ,不定期分享各类资源哦。

image-20211108230322493

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值