Java 核心技术-集合-集合框架

说在前面的话:

关于Core Java 集合方面的博文网上已经写烂了,为啥我还要写呢?

答:他们写的都很好,我也学到不少东西,如果把我当做一个系统的话,学习别人、看书、读源码是输入,但是往往形不成一个回路,形不成回路就会与行业脱节,所以我也要输出一些东西,尽管这些东西大家耳熟能详。

本文适合的读者?

答:会简单用Java 集合类库,看过core java volume 1但是不知其所以然的同学。

废话不多说,大家找你们感兴趣的点吧,也可以多多提提建议。




没有目录的博文都是耍流氓。

集合框架

视图与包装器

视图技术的应用

  轻量级集包装器

  子范围

  不可修改的视图

  同步视图

  检查视图

  关于可选操作的说明

批处理

数组与集合之间的转换

集合框架

框架是一个类的集,它奠定了创建高级功能的基础。框架包含很多超类,这些超类拥有非常有用的功能、策略和机制。框架使用者创建的子类可以扩展超类的功能,而不必重新创建这些有用的机制。

Java集合类库中有很多有用的接口、抽象类和具体类,这些对使用者来说非常有帮助,你需要用的时候直接拿来用就可以了,需要扩展功能的实现相应的接口和扩展类即可。

集合类库的接口关系图这里就不画了,基本的接口有Collection和Map。还有Iterator接口。这些接口被一些更具体的接口继承,来提供某种具体集合的服务。除此之外,还有一个标记接口RandomAccess,这个接口没有任何方法,只是用来检测一个特定的集合是否支持高效的随机访问。

视图与包装器

使用视图可以获得其他的实现了集合接口和映射表接口的对象。

例如:映射表类的keySet方法,看起来好像它创建了一个新集(Set),并将映射表中的所有键都填进去,然后返回这个集。事实是该方法返回一个实现Set接口的类对象,这个类方法对原映射表进行操作。这种集合就称为视图。

视图技术的应用

轻量级集包装器

Arrays类的静态方法asList将返回一个包装了普通Java数组的List包装器,该方法可以将数组传递给一个希望得到列表或者集合变量的方法。

1 String[] values = new String[10];
2 List<String> aList = Arrays.asList(values);

返回的对象不是ArrayList,而是一个视图对象,带有访问底层数组的get和set方法。改变数组大小的所有方法都会抛出一个异常(不支持的操作)。

源码解析:

// Arrays asList方法源码
@SafeVarargs
public static <T> List<T> asList(T... a) {
// 返回构造的ArrayListd对象,注意构造方法的参数,并不是java.util.ArrayList支持的参数。
        return new ArrayList<>(a);
}

这里使用的ArrayList类是Arrays的内部类

private static class ArrayList<E> extends AbstractList<E>
        implements RandomAccess, java.io.Serializable
    {
        private static final long serialVersionUID = -2764017481108945198L;
        private final E[] a;
        ArrayList(E[] array) { // 构造函数接收数组作为参数
            if (array==null)
                throw new NullPointerException();
            a = array;
        }
        public Object[] toArray() {  //默认的toArray方法返回Object[]
            return a.clone();
        }
        public <T> T[] toArray(T[] a) {  //返回传入参数类型的数组
            int size = size();
            if (a.length < size)
                return Arrays.copyOf(this.a, size,
                                     (Class<? extends T[]>) a.getClass());
            System.arraycopy(this.a, 0, a, 0, size);
            if (a.length > size)
                a[size] = null;
            return a;
        }
     // 没有覆盖add remove等改变数组大小的方法
     // get set indexof contains 方法省略……
     }

为什么改变数组的大小的方法会抛出异常呢? ArrayList<E> 继承自AbstractList类,AbstractList类中定义的改变数组大小的方法默认抛出异常。

public void add(int index, E element) {
        throw new UnsupportedOperationException();
}
public E remove(int index) {
        throw new UnsupportedOperationException();
}

下一个操作,Collections.nCopies();

List<anObject> oList = Collections.nCopies(n,anObject);

将返回一个实现了List接口的不可修改的对象(不能修改引用,并没说对象本身不可以修改)。

该方法和Arrays.asList()方法类似,也是返回一个内部类(CopiesList)的对象,该内部类继承AbstractList类,没有覆盖修改对象的方法(所以不支持修改该对象)

public static <T> List<T> nCopies(int n, T o) {
        if (n < 0)
            throw new IllegalArgumentException("List length = " + n);
        return new CopiesList<>(n, o);
}
private static class CopiesList<E>
        extends AbstractList<E>
        implements RandomAccess, Serializable
    {
        private static final long serialVersionUID = 2739099268398711800L;
        final int n;
        final E element;  // 只有这一个元素,对外看起来就像是有n个元素一样
        CopiesList(int n, E e) {
            assert n >= 0;
            this.n = n;
            element = e;
        }
        public boolean contains(Object obj) {
            return n != 0 && eq(obj, element);
        }
        public int indexOf(Object o) {
            return contains(o) ? 0 : -1;
        }
        public int lastIndexOf(Object o) {
            return contains(o) ? n - 1 : -1;
        }
        public E get(int index) {
            if (index < 0 || index >= n)
                throw new IndexOutOfBoundsException("Index: "+index+ ", Size: "+n);
            return element;
        }
        public Object[] toArray() {
            final Object[] a = new Object[n];
            if (element != null)
                Arrays.fill(a, 0, n, element);
            return a;
        }
        public <T> T[] toArray(T[] a) {
            final int n = this.n;
            if (a.length < n) {
                a = (T[])java.lang.reflect.Array
                    .newInstance(a.getClass().getComponentType(), n);
                if (element != null)
                    Arrays.fill(a, 0, n, element);
            } else {
                Arrays.fill(a, 0, n, element);
                if (a.length > n)
                    a[n] = null;
            }
            return a;
        }
        public List<E> subList(int fromIndex, int toIndex) {
            if (fromIndex < 0)
                throw new IndexOutOfBoundsException("fromIndex = " + fromIndex);
            if (toIndex > n)
                throw new IndexOutOfBoundsException("toIndex = " + toIndex);
            if (fromIndex > toIndex)
                throw new IllegalArgumentException("fromIndex(" + fromIndex + ") > toIndex(" + toIndex + ")");
            return new CopiesList<>(toIndex - fromIndex, element);
        }
}

同理 Collections 类中还有很多方法都是按照类似的节奏来对外提供服务的,Collections.singleton(anObject); 返回一个视图对象,该对象实现了Set<E>接口,其实是继承了AbstractSet抽象类。返回的对象实现了一个不可修改的单元素集。

singletonList方法和singletonMap方法类似。具体请参见Collections源代码。

(源码面前,了无秘密)

子范围

很多集合都支持建立子范围(subrange)视图。对于列表,可以使用subList方法来获得一个列表的子范围视图。

List<String> group = aList.subList(10,20);

可以将任何操作应用于子范围(包括改变列表大小,也可以清空),并且能够自动反映整个列表的情况(因为子范围返回的对象是列表内部类的对象,也就是列表的视图,它们共用一份数组。)

对于有序集和映射表,可以使用排序顺序而不是元素位置建立子范围。

SortedSet<E>  subSet(E from,E to)
SortedSet<E>  headSet(E to)
SortedSet<E>  tailSet(E from)
SortedMap<K,V>  subMap(K from , K to)
SortedMap<K,V>  headMap(K to)
SortMap<K,V>  tailMap(K from)

以上方法返回有序集和映射表的视图。

Java SE 6引入NavigableSet接口赋予子范围操作更多的控制能力。可以指定是否包含边界:

NavigableSet<E>  subSet(E from,boolean fromInclusive, E to, boolean toInclusive)
NavigableSet<E>  headSet(E to,boolean toInclusive)
NavigableSet<E>  tailSet(E from,boolean fromInclusive)

不可修改视图

Collections 还有几个方法用于产生集合的不可修改视图,这些视图对现有集合增加一个运行时的检查。如果发现试图对集合进行修改,就抛出一个异常,同时这个集合将保持未修改的状态。

这些方法有:

Collections.unmodifiableCollection
Collections.unmodifiableList
Collections.unmodifiableSet
Collections.unmodifiableSortedSet
Collections.unmodifiableMap
Collections.unmodifiableSortedMap

不可修改视图并不是集合本身不可修改。仍然可以通过集合的原始引用进行修改。

同步视图

由于普通集合类不能保证被多线程访问的安全性。

类库的设计者提供了一种视图机制保证常规集合的线程安全,而不是实现线程安全的集合类。例如: Collections类的静态synchronizedMap方法可以将任何一个映射表转换成具有同步访问方法的Map。

Map<String,Employee> map =
Collections.synchronizedMap(new HashMap<String,Employee>());

通过源码我们可以了解到,集合框架Collections 给我们提供了很多有用的内部类,这些内部类担当常规集合的同步视图,个人感觉有点像装饰者模式。为了让大家有一个直观的认识,这些同步内部类的继承结构如下图所示(原谅我作图实在是。):

检查视图

Java SE 5 增加了一组“检查”视图,用来对泛型类型发生问题时提供调试支持。

错误举例:

ArrayList<String> strings = new ArrayList<>();
ArrayList rawList = strings;
rawList.add(new Date());   // add不会出错,另一部分代码调用get方法,并转换为String 就会抛出异常了。

检查视图可以探测到这类问题。

List<String>  safeStrings = Collections.checkedList(strings,Sring.class);

原理其实很简单,在调用集合add方法之前检验下添加元素的类型和集合元素的类型是否匹配。

源码如下:

        void typeCheck(Object o) {
            if (o != null && !type.isInstance(o))
                throw new ClassCastException(badElementMsg(o));
        }
        private String badElementMsg(Object o) {
            return "Attempt to insert " + o.getClass() +
                " element into collection with element type " + type;
        }
        CheckedCollection(Collection<E> c, Class<E> type) {
            if (c==null || type == null)
                throw new NullPointerException();
            this.c = c;
            this.type = type;
        }

关于可选操作的说明

通常,视图有一些局限性,可能只可以读、无法改变大小、只支持删除而不支持插入,这些与映射表的键视图情况相同。如果试图进行恰当的操作,受限制视图就会抛出 UnsupportedOperationException。

这样很好的限制了接口数量的成倍增加。

批操作

使用类库中的批操作避免频繁的使用迭代器


集合批操作


批操作含义


retainAll(Collection<?> c):boolean


保留参数中不存在的元素


removeAll(Collection<?> c):boolean


删除参数中存在的元素


addAll(Collection<?> c):boolean


添加参数中存在的元素


clear():void


清空集合

集合与数组之间的转换

由于集合框架比Java平台的大部分API生的晚,所以有时候为了兼容,需要在传统的数组和现代的集合之间进行转换。

数组转换为集合,Arrays.asList的包装器可以实现:

String [] values = ...;
HashSet<String> staff = new HashSet<String>(Arrays,asList(values));

将集合转换为数组:

(1)   使用toArray方法

Object[] values = staff.toArray();

这样做的结果是产生一个对象数组。即使知道集合中包含一个特定类型的对象,也不能使用类型转换。

String[] values = (String[]) staff.toArray();  //error

toArray方法返回的数组是一个Object[]数组,无法改变其类型。

(2)   使用另外一种toArray方法,并将其设计为所希望的元素类型且长度为0的数组,随后所返回的数组将和所创建的数组一样:

String[] values = staff.toArray(new String[0]); // right
时间: 2024-11-02 23:34:26

Java 核心技术-集合-集合框架的相关文章

Java核心技术梳理-集合

目录 一.前言二.Collection 和 Iterator2.1 Collection2.2 Iterator2.3 foreach2.4 Predicate2.4 Stream三.Set3.1 HashSet3.2 LinkedHashSet3.2 TreeSet3.4 EnumSet3.5 性能选择四.List4.1 ArrayList .Vector.LinkedList五.Queue5.1 PriorityQueue5.2 ArrayDeque六.Map6.1 HashMap与Hash

Java核心技术点之集合框架

概述 Java集合框架由Java类库的一系列接口.抽象类以及具体实现类组成.我们这里所说的集合就是把一组对象组织到一起,然后再根据不同的需求操纵这些数据.集合类型就是容纳这些对象的一个容器.也就是说,最基本的集合特性就是把一组对象放一起集中管理.根据集合中是否允许有重复的对象.对象组织在一起是否按某种顺序等标准来划分的话,集合类型又可以细分为许多种不同的子类型. Java集合框架为我们提供了一组基本机制以及这些机制的参考实现,其中基本的集合接口是Collection接口,其他相关的接口还有Ite

JAVA基础之集合框架

集合框架(collections framework) 首先要明确,集合代表了一组对象(和数组一样,但数组长度不能变,而集合能).Java中的集合框架定义了一套规范,用来表示.操作集合,使具体操作与实现细节解耦. 其实说白了,可以把一个集合看成一个微型数据库,操作不外乎"增删改查"四种操作,我们在学习使用一个具体的集合类时,需要把这四个操作的时空复杂度弄清楚了,基本上就可以说掌握这个类了. 设计理念 主要理念用一句话概括就是:提供一套"小而美"的API.API需要对

java中的集合框架

由于数组具有属性单一,长度不可改变的缺点,于是在程序中我们使用集合来代替它. 集合中不可放入基本数据类型,基本数据类型都是通过自动拆包和自动装箱功能才能放入和取出集合. 分类:Collection接口和Map接口 Collection:存放单一值元素,又可分为list接口类型和set接口类型 list接口类型:存放元素是有序的可重复的,可通过循环来取出其中的元素,实现类ArrayList() set接口类型:hash值排列,存放元素是无序不可重复的,通过指针取出其中元素,实现类HashSet()

Java集合与框架总结与学习

林炳文Evankaka原创作品.转载请注明出处http://blog.csdn.net/evankaka 本文将主要讲解Java中集合的使用与区别,主要讲List.Set.Map的原理.使用方法.注意事项等. 一.Collection与Collectons的区别 Java集合框架是Java语言的重要组成部分,它包含了系统而完整的集合层次体系,封装了大量的数据结构的实现.深刻理解Java集合框架的组成结构及其中的实现类和算法,能极大提高程序员编码的能力.本章讲述Java集合框架,主要包括集合框架的

学java教程之集合框架

学编程吧学编程学IT教程之java教程集合框架发布了,欢迎通过xuebiancheng8.com来访问 java中的集合框架故名思议就是针对集合的框架.那什么是集合呢,前面已经学习过数组,没错,数组就是一组数据的集合,换句话说数组也是一种特殊的集合框架,可以完成集合的功能.那数组在使用的时候有没有不方便的地方呢,比方说数组有可能有满的时候,满了怎么办,我们是不是得自己写程序来更改数组的大小呢,而且还要把原来的数组赋值到新的数组的原来位置上,这样很明显数组用起来不是特别方便,很多功能得让我们自己去

菜鸟日记之 java中的集合框架

java中的集合框架图 如图所示:java中的集合分为两种Collection和Map两种接口 可分为Collection是单列集合和Map的双列集合 Collection单列集合:继承了Iterator接口所以具有了iterator()方法 ,该方法返回一个Iterator<T>,这个接口具有 HasNext (),next(),remove()3个方法可以在实现类里完成实现. hasNext():判断是否有下一个元素 cusor是当前的操作下标 next():读取下一个元素 remove(

Java中的集合框架(上)

Java中的集合框架概述 集合的概念: Java中的集合类:是一种工具类,就像是容器,存储任意数量的具有共同属性的对象. 集合的作用: 1.在类的内部,对数据进行组织: 2.简单的快速的搜索大数据量的条目: 3.有的集合接口,提供了一系列排列有序的元素,并且 可以在序列中间快速的插入或删除有关的元素. 4.有的集合接口,提供了映射关系,可以通过 关键字(key)去快速查找到对应的唯一对象,而这个关键字可以是任意类型. 与数组的对比一为何选择集合而不是数组 1.数组的长度固定,集合长度可变 2.数

java常见的集合框架有哪些?

java常见的集合框架有哪些?很多学习java的朋友会问到这个问题,那么学习Java集合框架下大致可以分为如下五个部分:List列表.Set集合.Map映射.迭代器(Iterator.Enumeration).工具类(Arrays.Collections).今天西安java培训小编为大家分享. Java集合类的整体框架如下: 从上图中可以看出,集合类主要分为两大类:Collection和Map. Collection是List.Set等集合高度抽象出来的接口,它包含了这些集合的基本操作,它主要又