[集合类] 源码解析1(Iterable、RandomAccess、Serializable、Cloneable)

集合类是我们每天都在使用的工具。工欲善其事,必先利其器。下面我们从源码的角度来看看集合类中的奥秘。

1. 整体

下面图片是整体的架构,这里只表现了类和接口类的继承实现关系,选取了平时使用比较多的类,如LinkedList、ArrayList、HashMap、TreeMap等,没有考虑并发容器。集合类分为两个体系,Collection和Map。我们先看Collection。

1)Collection

在这里插入图片描述
从上往下看,非常清晰,Collection实现了Iterable接口,也就是迭代器接口,我们后面再说。Collection有三个子接口,分别是List、Queue、Set。Collection、List、Queue、Set都有自己对应的抽象类。这里我们遇到了经典的问题,接口和抽象类的区别是什么?

抽象类是为了代码复用,将子类的共同方法组织到抽象类中,减少重复代码,抽象方法可以使结构上更加清晰,还可以使用多态的特性。

接口更注重的是行为抽象,降低代码之间的耦合性,提高可拓展性。从整体来讲,可以使调用者关注接口,而不是具体实现。

从开发角度来说,我们发现子类的代码重复,就会抽象出抽象父类来减少重复代码。而接口则是我们在设计系统时先确定好的,之后再考虑具体实现。

在这里插入图片描述

接下来就是一些中间接口。最下面就是我们平时常用的具体类。

在这里插入图片描述

这些类还实现了一些特殊的接口,我们后面再看。

在这里插入图片描述

2)Map

Map和Collection大同小异,这里只放一下整体架构,大家有个印象就好,后面我们详细再说。

在这里插入图片描述

2. Iterable

首先看一下接口定义。Iterable接口表示一种能力,具有迭代的能力。Iterable接口中有三个方法,其余两个和本文的内容无关,我们忽略。iterator方法用于返回一个迭代器,在各个容器中有各自的实现。真正的迭代器类是Iterator接口,其中定义了迭代器的基本操作,在各个容器中也有具体的迭代器实现,在后面的文章再具体分析。

public interface Iterable<T> {

    Iterator<T> iterator();
		// ...
}

public interface Iterator<E> {
    boolean hasNext();
  
    E next();

    default void remove() {
        throw new UnsupportedOperationException("remove");
    }
		// ...
}

3. RandomAccess、Serializable、Cloneable

从整体图中我们可以看到Cloneable、Serializable、 RandomAccess三个接口出场率很高。我们经常使用的类中,都至少实现了这三个接口中的一个。

在这里插入图片描述

在这里插入图片描述
翻看他们的定义,我们发现了一个共同的特征,三个接口都是空的!!

这种接口叫做标志接口,他不定义任何操作,只是起到一种标记作用。

public interface RandomAccess {
}

public interface Serializable {
}

public interface Cloneable {
}

下面我们看几个例子,体会一下。

1)RandomAccess

RandomAccess的意思是快速随机访问,官网中有解释。下面是Java Collections工具类中二分查找的实现,可以看到,如果容器支持快速随机访问,则会使用基于索引的二分查找,否则使用基于迭代的二分查找。

// java.util.Collections
public static <T> int binarySearch(List<? extends Comparable<? super T>> list, T key) {
    if (list instanceof RandomAccess || list.size()<BINARYSEARCH_THRESHOLD)
        return Collections.indexedBinarySearch(list, key);
    else
        return Collections.iteratorBinarySearch(list, key);
}

2)Serializable

Serializable标志一个类可以被序列化,数据在网络中传送是串行的,所以在网络中发送数据必须要进行序列化,接受数据要进行反序列化。下面的方法中,如果需要被序列化的对象没有实现Serializable接口,则会抛出NotSerializableException异常。

// java.io.ObjectOutputStream
/*** @throws  NotSerializableException Some object to be serialized does not
* 		implement the java.io.Serializable interface.
*/
public final void writeObject(Object obj) throws IOException {
  if (enableOverride) {
    writeObjectOverride(obj);
    return;
  }
  try {
    writeObject0(obj, false);
  } catch (IOException ex) {
    if (depth == 0) {
      writeFatalException(ex);
    }
    throw ex;
  }
}

3)Cloneable

祖宗类Object有个方法 clone(),他和Cloneable一起合作,用来实现Java中的克隆。使用场景参考不变模式如何实现不变性,第三。下面是一个简单的栗子。

class Student implements Cloneable{  
    private int number;  
  
    @Override  
    public Object clone() {  
        Student stu = null;  
        try{  
            stu = (Student)super.clone();
        }catch(CloneNotSupportedException e) {  
            e.printStackTrace();  
        }  
        return stu;  
    }  
} 

下一篇[集合类] 源码解析2(Iterator的常用实现)

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值