Java 基础接口(Serializable、Cloneable、RandomAccess)

一、 java.io.Serializable 接口

public interface Serializable {
}

实现 java.io.Serializable 接口的类是可序列化的。

序列化类的所有子类本身都是可序列化的。

Java序列化的目的主要有: 1.网络传输  2.对象持久化;

基于Java提供的ObjectInputStream/ObjectOutputStream 可以直接将Java对象作为可存储的字节数组写入文件,也可以传输到网络上。

基于JDK默认的序列化机制可以避免直接操作底层的字节数组,从而提升开发效率;

当进行远程跨进程服务调用时,需要把被传输的Java对象编码为字节数组或者ByteBuffer对象,而当远程服务读取到ByteBuffer对象或者字节数组时,需要将其解码为发送时的Java对象,这被称为Java编解码技术;

   # Java 序列化的缺点
   1. 无法跨语言;    RPC框架往往需要支持跨语言调用;
   2. 序列化后的码流太大;
   3. 序列化性能太低

   # 编解码框架的优劣:
   1. 是否支持跨语言,支持的语言种类是否丰富
   2. 编码后的码流大小
   3. 编解码的性能
   4. 类库是否小巧,API使用是否方便
   5. 使用者需要手工开发的工作量和难度

   XML 解析的时间开销 和 XML 为了可读性而牺牲的空间开销都非常大,因此不适合做高性能的通信协议;

   # Google ProtoBuf  使用 二进制编码
   # FaceBoook Thrift
   # JBoss Marshalling

 

二、java.lang.Cloneable 接口

public interface Cloneable {
}

Cloneable是一个标记接口,没有定义任何方法。原因是: 在Java中,所有类的终极父类 java.lang.Object 已经将clone()方法定义为所有类都应该具有的基本功能,只是将该方法声明为了protected类型。该方法定义了逐字段拷贝实例的操作。它是一个native本地方法,因此没有实现体,而且在拷贝字段时,除了Object类的字段外,其子类的新字段也将被拷贝到新的实例中。

既然Object类中已经有了 clone() 方法,为什么还是需要让想具备实力拷贝功能的类实现Cloneable接口呢?其实,Cloneable接口在这里起到了一种标识的作用,表明实现它的类具备了实例拷贝功能,在Cloneable接口的官方javadoc文档中有这样一段话:

       "Invoking Object's clone method on an instance that does not implement the Cloneable interface results in the exception CloneNotSupportedException being thrown. JDK1.8"

也就是说,如果一个类不实现该接口就直接调用clone()方法的话,即便已将clone()方法重写为public,那还是会抛出“CloneNotSupportedException”异常。因此,要想使一个类具备拷贝实例的功能,那么除了要重写Object类的clone()方法 ,把clone()方法修改为public外,还必须要实现Cloneable接口;

1. 浅拷贝

在java中,对象创建后需要有一个引用变量来指向该对象实际的地址空间,也就是说引用变量与对象实体是两个不同的数据体。在Object类的clone()方法中,对对象字段进行复制时,如果字段是基本数据类型(如int、double等),则会复制字段的值到一个新的变量中,而字段是引用类型,则仅会将引用值复制给新对象中的相应字段中,也就是说,两个字段指向了同一个对象实例。

package com.fast.java.a00;

import org.junit.Test;

public class Clone_Test {

    /**
     * 在java中,对象创建后需要有一个引用变量来指向该对象实际的地址空间,也就是说引用变量与对象实体
     * 是两个不同的数据体。在Object类的clone()方法中,对对象字段进行复制时,如果字段是基本数据类型
     * (如int、double等),则会复制字段的值到一个新的变量中,而字段是引用类型,则仅会将引用值复制
     * 给新对象中的相应字段中,也就是说,两个字段指向了同一个对象实例。
     */
    @Test
    public void test_ShallowClone() throws CloneNotSupportedException {

        UserInfo dataObj = new UserInfo("original data");
        StringBuffer strBuf = new StringBuffer("origin data");

        ShallowCloneClass objOrigin = new ShallowCloneClass(dataObj, 1.0, "original", strBuf);
        ShallowCloneClass objCopy = null;
        Object objTemp = objOrigin.clone();
        if (objTemp instanceof ShallowCloneClass) {
            objCopy = (ShallowCloneClass)objTemp;
        }

        /**
         * false说明copy和org是两个不同的对象实例
         * (对于引用类型的比变量,“==”判断的是对象地址是否相同,也就是是不是指向了同一个对象)
         */
        System.out.println("objCopy == objOrigin? " + (objCopy == objOrigin));
        System.out.println();

        System.out.println("data of objOrigin:");
        objOrigin.show();
        System.out.println();
        System.out.println("data of objCopy:");
        objCopy.show();

        /**
         * 但是他们字段的值却是相同的。objCopy和objOrigin各字段的“==”判断全为true也说明本地Object本地
         * clone()对实例引用型字段进行的是浅拷贝。
         */
        System.out.println();
        System.out.println("objOrigin.dataObj == objCopy.dataObj? " + (objOrigin.dataObj == objCopy.dataObj));
        System.out.println("objOrigin.dataDbl == objCopy.dataDbl? " + (objOrigin.dataDbl == objCopy.dataDbl));
        System.out.println("objOrigin.dataStr == objCopy.dataStr? " + (objOrigin.dataStr == objCopy.dataStr));
        System.out.println("objOrigin.dataStrBuf == objCopy.dataStrBuf? " + (objOrigin.dataStrBuf == objCopy.dataStrBuf));


        // 修改copy中各字段指向对象的属性
        objCopy.dataObj.userData = "Copy data";
        objCopy.dataDbl = 2.0;
        objCopy.dataStr = "Copy";
        objCopy.dataStrBuf.replace(0, objCopy.dataStrBuf.length(), "Copy data");

        /**
         * 由于CloneableClass的dataObj和dataStrBuf字段均为引用型变量,所以通过objOrigin浅拷贝出来的
         * objCopy实例中的dataObj和dataStrBuf字段与 objOrigin 中的相应字段实际上指向的是同一个对象,
         * 因此,objCopy 对成员对象的修改也就导致了objOrigin 中相应成员对象的随之改变。
         * 需要说明的是,dataStr 虽然也是引用型变量,但由于字符串是常量,所以语句
         * objCopy.dataStr = “Copy”并没有对原字符串进行修改,
         * 而是将objCopy的 dataStr字段指向了一个新的字符串“Copy”。
         */
        System.out.println();
        System.out.println("After modify, data of original:");
        objOrigin.show();
        System.out.println();
        System.out.println("After modify, data of copy:");
        objCopy.show();
    }
}

class ShallowCloneClass implements Cloneable {

    public UserInfo     dataObj = null;
    public double       dataDbl = 0;
    public String       dataStr = null;
    public StringBuffer dataStrBuf = null;

    public ShallowCloneClass(UserInfo dataObj, double dataDbl, String dataStr, StringBuffer dataStrBuf) {
        this.dataObj = dataObj;
        this.dataDbl = dataDbl;
        this.dataStr = dataStr;
        this.dataStrBuf = dataStrBuf;
    }

    public void show() {
        System.out.println("dataObj = " + dataObj.userData);
        System.out.println("dataDbl = " + dataDbl);
        System.out.println("dataStr = " + dataStr);
        System.out.println("dataStrBuf = " + dataStrBuf);
    }

    /**
     * 重写clone()方法为public类型,并调用Object的本地clone()方法,实现浅拷贝功能
     */
    @Override
    public Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

class UserInfo {

    public String userData = null;

    public UserInfo(String userData) {
        this.userData = userData;
    }
}


输出结果:
objCopy == objOrigin? false

data of objOrigin:
dataObj = original data
dataDbl = 1.0
dataStr = original
dataStrBuf = origin data

data of objCopy:
dataObj = original data
dataDbl = 1.0
dataStr = original
dataStrBuf = origin data

objOrigin.dataObj == objCopy.dataObj? true
objOrigin.dataDbl == objCopy.dataDbl? true
objOrigin.dataStr == objCopy.dataStr? true
objOrigin.dataStrBuf == objCopy.dataStrBuf? true

After modify, data of original:
dataObj = Copy data
dataDbl = 1.0
dataStr = original
dataStrBuf = Copy data

After modify, data of copy:
dataObj = Copy data
dataDbl = 2.0
dataStr = Copy
dataStrBuf = Copy data

2. 深拷贝

从上文讲的浅拷贝概念与性质中不难退出深拷贝的含义,那就是

对于引用型变量,深拷贝会开辟一块新的内存空间,将被复制引用所指向的对象实例的各个属性复制到新的内存空间中,然后将新的引用指向块内存(也就是一个新的实例)。

要想实现深拷贝的功能,我们在重写clone()方法的时候,就不能再简单地调用Object的本地clone()方法,而是要对上文中的CloneableClass做如下修改:

class DeepCloneClass implements Cloneable {

    public UserInfo       dataObj = null;
    public double       dataDbl = 0;
    public String       dataStr = null;
    public StringBuffer dataStrBuf = null;

    public DeepCloneClass(UserInfo dataObj, double dataDbl, String dataStr, StringBuffer dataStrBuf) {
        this.dataObj = dataObj;
        this.dataDbl = dataDbl;
        this.dataStr = dataStr;
        this.dataStrBuf = dataStrBuf;
    }

    public void show() {
        System.out.println("dataObj = " + dataObj.userData);
        System.out.println("dataDbl = " + dataDbl);
        System.out.println("dataStr = " + dataStr);
        System.out.println("dataStrBuf = " + dataStrBuf);
    }

    /**
     * 重写clone()方法为public类型,对每一个字段都创建一个新的对象,并将原字段指向对象中的属性
     * 复制到新的对象中,从而实现深拷贝功能。
     */
    @Override
    public Object clone() throws CloneNotSupportedException {
        UserInfo     dataObj    = new UserInfo(this.dataObj.userData);
        double       dataDbl    = this.dataDbl;
        String       dataStr    = new String(this.dataStr);
        StringBuffer dataStrBuf = new StringBuffer(this.dataStrBuf.toString());

        DeepCloneClass deepCopy = new DeepCloneClass(dataObj, dataDbl, dataStr, dataStrBuf);

        return deepCopy;
    }
}

@Test
public void test_DeepClone() throws CloneNotSupportedException {

    UserInfo dataObj = new UserInfo("original");
    StringBuffer strBuf = new StringBuffer("origin");

    DeepCloneClass objOrigin = new DeepCloneClass(dataObj, 1.0, "original", strBuf);
    DeepCloneClass objCopy = null;
    Object objTemp = objOrigin.clone();
    if (objTemp instanceof DeepCloneClass) {
        objCopy = (DeepCloneClass)objTemp;
    }

    /**
     * false说明copy和org是两个不同的对象实例
     * (对于引用类型的比变量,“==”判断的是对象地址是否相同,也就是是不是指向了同一个对象)
     */
    System.out.println("objCopy == objOrigin? " + (objCopy == objOrigin));
    System.out.println();

    System.out.println("objOrigin.dataObj == objCopy.dataObj? " + (objOrigin.dataObj == objCopy.dataObj));
    System.out.println("objOrigin.dataDbl == objCopy.dataDbl? " + (objOrigin.dataDbl == objCopy.dataDbl));
    System.out.println("objOrigin.dataStr == objCopy.dataStr? " + (objOrigin.dataStr == objCopy.dataStr));
    System.out.println("objOrigin.dataStrBuf == objCopy.dataStrBuf? " + (objOrigin.dataStrBuf == objCopy.dataStrBuf));

    System.out.println();


    // 修改copy中各字段指向对象的属性
    objCopy.dataObj.userData = "Copy data";
    objCopy.dataDbl = 2.0;
    objCopy.dataStr = "Copy";
    objCopy.dataStrBuf.replace(0, objCopy.dataStrBuf.length(), "Copy data");

    System.out.println("After modify, data of original:");
    objOrigin.show();
    System.out.println();
    System.out.println("After modify, data of copy:");
    objCopy.show();
}


输出结果:
objCopy == objOrigin? false

objOrigin.dataObj == objCopy.dataObj? false
objOrigin.dataDbl == objCopy.dataDbl? true
objOrigin.dataStr == objCopy.dataStr? false
objOrigin.dataStrBuf == objCopy.dataStrBuf? false

After modify, data of original:
dataObj = original
dataDbl = 1.0
dataStr = original
dataStrBuf = origin

After modify, data of copy:
dataObj = Copy data
dataDbl = 2.0
dataStr = Copy
dataStrBuf = Copy data

 

三、 java.util.RandomAccess  接口

public interface RandomAccess {
}

实现 RandomAccess接口, 用来表明其支持快速(通常是固定时间)随机访问。

JDK中推荐的是对List集合尽量要实现RandomAccess接口;

如果集合类是RandomAccess的实现,则尽量用for(int i = 0; i < size; i++) 来遍历而不要用Iterator迭代器来遍历,在效率上要差一些。反过来,如果List是Sequence List,则最好用迭代器来进行迭代。

JDK中说的很清楚,在对List特别是Huge size的List的遍历算法中,要尽量来判断是属于RandomAccess(如ArrayList)还是Sequence List (如LinkedList),因为适合RandomAccess List的遍历算法,用在Sequence List上就差别很大,常用的作法就是:

if (list instance of RandomAccess) {
    for(int m = 0; m < list.size(); m++){
    }
}else{
    Iterator iter = list.iterator();
    while(iter.hasNext()){
    }
}
package com.fast.java.a00;

import java.util.*;

public class RandomAccess_Test {

    public static void main(String[] args) {
        ArrayList arraylist = new ArrayList();
        LinkedList linkedlist = new LinkedList();
        initList(arraylist, 1000);
        initList(linkedlist, 1000);

        traverse(arraylist);
        traverse(linkedlist);

        System.out.println("迭代 arraylist: ");
        traverseWithIterator(arraylist);
        traverseWithLoop(arraylist);

        System.out.println("迭代 linkedlist: ");
        traverseWithIterator(linkedlist);
        traverseWithLoop(linkedlist);
    }

    public static void traverse(List list) {
        long starttime = 0;
        long endtime = 0;
        if (list instanceof RandomAccess) {
            System.out.println("该list实现了RandomAccess接口");
            starttime = System.currentTimeMillis();
            for (int count = 0; count <= 1000; count++) {
                for (int i = 0; i < list.size(); i++) {
                    list.get(i);
                }
            }
            endtime = System.currentTimeMillis();
            System.out.println("\tLoop 迭代一共花了" + (endtime - starttime) + "ms时间");
        } else {
            System.out.println("该list未实现RandomAccess接口");
            starttime = System.currentTimeMillis();
            for (int count = 0; count <= 1000; count++) {
                for (Iterator itr = list.iterator(); itr.hasNext();) {
                    itr.next();
                }
            }
            endtime = System.currentTimeMillis();
            System.out.println("\tIterator 迭代一共花了" + (endtime - starttime) + "ms时间");
        }
    }

    public static void initList(List list, int n) {
        for (int i = 0; i < n; i++) {
            list.add(i);
        }
    }

    //使用循环进行对列表的迭代
    public static void traverseWithLoop(List list) {
        long starttime = 0;
        long endtime = 0;
        starttime = System.currentTimeMillis();
        for (int count = 0; count <= 1000; count++) {
            for (int i = 0; i < list.size(); i++) {
                list.get(i);
            }
        }
        endtime = System.currentTimeMillis();
        System.out.println("\t使用loop迭代一共花了" + (endtime - starttime) + "ms时间");
    }

    //使用迭代器对列表进行迭代
    public static void traverseWithIterator(List list) {
        long starttime = 0;
        long endtime = 0;
        starttime = System.currentTimeMillis();
        for (int count = 0; count <= 1000; count++) {
            for (Iterator itr = list.iterator(); itr.hasNext();) {
                itr.next();
            }
        }
        endtime = System.currentTimeMillis();
        System.out.println("\t使用Iterator迭代一共花了" + (endtime - starttime) + "ms时间");
    }
}

输出结果:
该list实现了RandomAccess接口
	Loop 迭代一共花了11ms时间
该list未实现RandomAccess接口
	Iterator 迭代一共花了12ms时间
迭代 arraylist: 
	使用Iterator迭代一共花了16ms时间
	使用loop迭代一共花了10ms时间
迭代 linkedlist: 
	使用Iterator迭代一共花了21ms时间
	使用loop迭代一共花了334ms时间

 

参考文章: http://blog.csdn.net/u013916933/article/details/51590332

                  http://blog.csdn.net/keda8997110/article/details/8635005

转载于:https://my.oschina.net/zfscofield/blog/1593805

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值