基础篇-java优势,类初始化,克隆

1   java与C和C++相比的优势------------------------------begin----------------------------------

 1.1   java纯面向对象,万事万物皆对象

 1.2   平台无关性: 编译器把java代码编译为中间代码(字节码),字节码与平台无关,在java虚拟机(JVM)上即可执行

 1.3  提供了很多内置类库,简化了开发人员的程序设计工作,缩短了项目开发时间:如多线程,网络通信,垃圾回收(GC),最重要的是提供了GC,这是得开发人员从对内存的管理中解脱出来。

 1.4  提供了web应用开发的支持

   Applet,Servlet和JSP可以用来开发web应用程序

  Socket,RMI可以用来开发分布式应用程序的类库

 1.5  具有较好的安全性和健壮性

   java提供了一个防止恶意代码工具的安全机制,强制类型转换,垃圾回收器,异常处理,安全检查机制,使得java程序有很好的健壮性。

 1.6  去除了c++中难以理解,容易混淆的特性,如头文件,指针,结构,单元,运算符重载,多重继承等,使程序根据严谨,简洁。

 

2  类初始化顺序-----------------------------begin-------------------------------------

 实例化对象时,对象所在类的所有成员变量首先要进行初始化,初始化完成后,才会调用构造函数创建对象

 原则:1 静态优先   2父类优先于子类 3 按成员变量定义顺序初始化

 顺序:

        父类静态变量>父类静态代码块>子类静态变量>子类静态代码块>父类非静态变量>父类非静态代码块

>父类构造函数>子类非静态变量>子类非静态代码块>子类构造函数 

 

3 克隆对象-------------------------------begin-----------------------------------------

    3.1 目的:

     我们总会需要某个新的对象B,拥有和原对象A一样的状态,但修改新对象B时不改变原对象A的状态。

  我们可以new一个新对象B,然后把原对象A的属性一个个手动赋值给新对象B,但很繁琐。

所以才有了 克隆   用克隆造出一个对象副本。

   3.2 如何实现:

   方法1 Object 自带浅克隆方法 

protected native Object clone() throws CloneNotSupportedException;

说明:1.这是一个navtive方法  2.要使用该方法必须继承Object类,因为修饰符为protected  3.返回值为Object,需要强转

浅度克隆

public class Empolyee implements Serializable,Cloneable {
    private static final long serialVersionUID = 199958867467854597L;
    //职位
    private String title;
    //人员
    private Person person;
    /**
     * 克隆方法
     * @return
     */
    @Override
    protected Object clone() {
        Empolyee empolyee = null;
        try {
            empolyee = (Empolyee) super.clone();
            //引用类型
           // empolyee.setPerson((Person)person.clone());
            return empolyee;
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return null;
    }

如上图,调用了超类的clone方法

    //克隆测试类
    public void shallowCloneTest() throws Exception {
        //初始化对象
        Empolyee empolyeeOld = new Empolyee();
        Person person = new Person();
        person.setAge("18");
        person.setSex("男");
        person.setName("小铁");
        empolyeeOld.setPerson(person);
        empolyeeOld.setTitle("高中学生");

        //克隆对象
        Empolyee employeeNew = (Empolyee)empolyeeOld.clone();
        System.out.println("原对象="+JsonUtils.toJson(empolyeeOld));
        employeeNew.getPerson().setAge("40");
        employeeNew.getPerson().setName("老铁");
        System.out.println("修改新对象 年龄=40,姓名=老铁");
        System.out.println("原对象="+JsonUtils.toJson(empolyeeOld));
        System.out.println("新对象="+JsonUtils.toJson(employeeNew));
    }

浅克隆测试,输出结果

原对象={"person":{"age":"18","name":"小铁","sex":"男"},"title":"高中学生"}
修改新对象 年龄=40,姓名=老铁,职位=上市公司CEO
原对象={"person":{"age":"40","name":"老铁","sex":"男"},"title":"高中学生"}
新对象={"person":{"age":"40","name":"老铁","sex":"男"},"title":"上市公司CEO"}

     可以看到改了新对象的Person属性 年龄,姓名  原对象也改了

改了新对象的职位,原对象职位值未变

得出结论  Object的clone 方法是浅克隆,只克隆基础数据类型,其中新对象中引用类型和数组都还是指向原对象的引用。

 

方法2  用clone做深度克隆

还是用clone方法,但对复杂类型的属性,单独再克隆一次

    /**
     * 克隆方法
     * @return
     */
    @Override
    public Object clone() {
        Empolyee empolyee = null;
        try {
            empolyee = (Empolyee) super.clone();
            //复杂类型属性克隆
            empolyee.setPerson((Person)person.clone());
            return empolyee;
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return null;
    }

继续运行克隆测试类

测试结果
原对象={"person":{"age":"18","name":"小铁","sex":"男"},"title":"高中学生"}
修改新对象 年龄=40,姓名=老铁,职位=上市公司CEO
原对象={"person":{"age":"18","name":"小铁","sex":"男"},"title":"高中学生"}
新对象={"person":{"age":"40","name":"老铁","sex":"男"},"title":"上市公司CEO"}

 可以看出,修改了新对象不管是基本数据类型,还是引用类型的值,原对象都不会改变

可以得出结论,此为深度克隆

但是这种方式很繁琐,如果有大量复杂类型的成员变量(类属性),那就要分别对各属性克隆。所以我们应该找更好的方法来做 深度克隆。

 

方法3  用序列化方式做深度克隆

    /**
     * 深度克隆方法
     *
     * @param needCloneObject 需要克隆对象
     * @return
     */
    public static Object deepClone(Object needCloneObject) throws Exception {
        Object objNewOne = null;
        if (needCloneObject != null) {
            //把对象序列化为字节流
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(baos);
            oos.writeObject(needCloneObject);
            oos.close();

            //把字节流反序列化为对象
            ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
            ObjectInputStream ois = new ObjectInputStream(bais);
            objNewOne = ois.readObject();
            ois.close();
        }

        return objNewOne;
    }

调用测试方法

    @Test
    public void cloneTest() throws Exception {
        //初始化对象
        Empolyee empolyeeOld = new Empolyee();
        Person person = new Person();
        person.setAge("18");
        person.setSex("男");
        person.setName("小铁");
        empolyeeOld.setPerson(person);
        empolyeeOld.setTitle("高中学生");

        //调用序列化深度克隆方法  克隆对象
        Empolyee employeeNew = (Empolyee)deepClone(empolyeeOld);
        System.out.println("原对象="+JsonUtils.toJson(empolyeeOld));
        employeeNew.getPerson().setAge("40");
        employeeNew.getPerson().setName("老铁");
        employeeNew.setTitle("上市公司CEO");
        System.out.println("修改新对象 年龄=40,姓名=老铁,职位=上市公司CEO");
        System.out.println("原对象="+JsonUtils.toJson(empolyeeOld));
        System.out.println("新对象="+JsonUtils.toJson(employeeNew));
    }
输出结果

原对象={"person":{"age":"18","name":"小铁","sex":"男"},"title":"高中学生"}
修改新对象 年龄=40,姓名=老铁,职位=上市公司CEO
原对象={"person":{"age":"18","name":"小铁","sex":"男"},"title":"高中学生"}
新对象={"person":{"age":"40","name":"老铁","sex":"男"},"title":"上市公司CEO"}

可以看出,修改了新对象不管是基本数据类型,还是引用类型的值,原对象都不会改变,为深度克隆

而且此种方式的性能也做好,所以强烈推荐使用。

------------------------------------------克隆 end-----------------------------------------

 

posted on 2019-12-10 23:52  鑫男  阅读(152)  评论(0编辑  收藏  举报

导航