之前介绍了java容器类库的概念和基本功能,这些对于容器的使用来说已经足够了。本章将更深入的探索这个重要的类库。

一、完整的容器分类法

下面是集合类库更加完备的图。包括抽象类和遗留构件(不包括Queue的实现):

java SE5新添加了:

  • Queue接口(正如之前所介绍,LinkedList已经为实现该接口做了修改)及其实现PriorityQueue和各种风格的BlockingQueue,其中BlockingQueue将在并发中介绍。
  • ConcurrentMap接口及其实现ConcurrentHashMap,它们也是用于多线程机制的,同样会在并发中介绍。
  • CopyOnWriteArrayList和CopyOnWriteArraySet,它们也是用于多线程机制的。
  • EnumSet和EnumMap,为使用enum而设计的Set和Map的特殊实现,将在枚举类型中介绍。
  • 在Collections类中的多个便利方法。

虚线框表示abstract类,你可以看到大量的类的名字都是以Abstract开头的。这些类可能初看起来有点令人困惑,但是它们只是部分实现了特定接口的工具。例如,如果你在创建自己的Set,那么并不用从Set接口开始并实现其中的全部方法,只需从AbstractSet继承,然后执行一些创建新类必需的工作。但是,事实上容器类库包含足够多的功能,任何时刻都可以满足你的需求,因此你通常可以忽略以Abstract开头的这些类。

二、填充容器

虽然容器打印的问题解决了,容器的填充仍然像java.util.Arrays一样面临同样的不足。就像Arrays一样,相应的Collections类也有一些实用的static方法,其中包括fill()。与Arrays版本一样,此fill()方法也是只复制同一个对象引用来填充整个容器的,并且只对List对象有用,但是所产生的列表可以传递给构造器或addAll()方法:

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;class StringAddress {private String s;public StringAddress(String s) {this.s = s;}public String toString() {return super.toString() + " " + s;}
}public class FillingLists {public static void main(String[] args) {List<StringAddress> list = new ArrayList<>(Collections.nCopies(4, new StringAddress("Hello")));System.out.println(list);Collections.fill(list, new StringAddress("World!"));System.out.println(list);}
}

这个示例展示了两种用于单个对象的引用来填充Collection的方式,第一种是使用Collections.nCopies()创建传递给构造器的List,这里填充的是ArrayList。

StringAddress的toString()方法调用Object.toString()并产生该类的名字,后面紧跟该对象的散列码的无符号十六进制表示(通过hashCode()生成的)。从输出中你可以看到所有引用都被设置为指向相同的对象,在第二种方法的Collection.fill()被调用之后也是如此。fill()方法的用处更有限,因为它只能替换已经在List中存在的元素,而不能添加新的元素。

三、一种Generator解决方案

事实上,所有的Collection子类型都有一个接受另一个Collection对象的构造器,用所接收的Collection对象中的元素来填充新的容器。为了更加容易地创建测试数据,我们需要做的是构建接收Generator和quantity数值并将它们作为构造器参数的类:

import java.util.ArrayList;public class CollectionData<T> extends ArrayList<T> {public CollectionData(Generator<T> gen, int quantity) {for (int i = 0; i < quantity; i++) {add(gen.next());}}public static <T> CollectionData<T> list(Generator<T> gen, int quantity) {return new CollectionData<T>(gen, quantity);}
}

这个类使用Generator在容器中放置所需数量的对象,然后所产生的容器可以传递给任何Collection的构造器,这个构造器会把其中的数据复制到自身中。addAll()方法是所有Collection子类型的一部分,它也可以用来组装现有的Collection。

泛型便利方法可以减少在使用类时所必需的类型检查数量。

CollectionData是适配器设计模式的一个实例,它将Generator适配到Collection的构造器上。

下面是初始化LinkedHashSet的一个示例:

import java.util.LinkedHashSet;
import java.util.Set;import com.buba.util.CollectionData;
import com.buba.util.Generator;class Government implements Generator<String> {String[] foundation = "strange women lying in ponds distributing swords is no basis for a system of government".split(" ");private int index;@Overridepublic String next() {return foundation[index++];}}public class CollectionDataTest {public static void main(String[] args) {Set<String> set = new LinkedHashSet<>(new CollectionData<String>(new Government(), 15));set.addAll(CollectionData.list(new Government(), 15));System.out.println(set);}
}

这些元素的顺序与它们的插入顺序相同,因为LinkedHashSet维护的是保持了插入顺序的链接列表。

在数组中定义的所有操作符现在通过CollectionData适配器都是可用的。下面是使用了其中两个操作符的示例:

import java.util.ArrayList;
import java.util.HashSet;import com.buba.util.CollectionData;
import com.buba.util.RandomGenerator;public class CollectionDataGeneration {public static void main(String[] args) {System.out.println(new ArrayList<String>(CollectionData.list(new RandomGenerator.String(9), 10)));System.out.println(new HashSet<Integer>(new CollectionData<Integer>(new RandomGenerator.Integer(), 10)));}
}

RandomGenerator.String所产生的String长度是通过构造器参数控制的。

四、Map生成器

我们可以对Map使用相同的方式,但是这需要有一个Pair类,因为为了组装Map,每次调用Generator的next()方法都必须产生一个对象对(一个键和一个值):

public class Pair<K, V> {public final K key;public final V value;public Pair(K k, V v) {key = k;value = v;}
}

key和value域都是public和final的,这是为了使Pair成为只读的数据传输对象(或信使)。

Map适配器现在可以使用各种不同的Generator、Iterator和常量值的组合来填充Map初始化对象:

import java.util.LinkedHashMap;public class MapData<K, V> extends LinkedHashMap<K, V> {public MapData(Generator<Pair<K, V>> gen, int quantity) {for (int i = 0; i < quantity; i++) {Pair<K, V> p = gen.next();put(p.key, p.value);}}public MapData(Generator<K> genK, Generator<V> genV, int quantity) {for (int i = 0; i < quantity; i++) {put(genK.next(), genV.next());}}public MapData(Generator<K> genK, V value, int quantity) {for (int i = 0; i < quantity; i++) {put(genK.next(), value);}}public MapData(Iterable<K> genK, Generator<V> genV) {for (K k : genK) {put(k, genV.next());}}public MapData(Iterable<K> genK, V value) {for (K k : genK) {put(k, value);}}public static <K, V> MapData<K, V> map(Generator<Pair<K, V>> gen, int quantity) {return new MapData<K, V>(gen, quantity);}public static <K, V> MapData<K, V> map(Generator<K> genK, Generator<V> genV, int quantity) {return new MapData<K, V>(genK, genV, quantity);}public static <K, V> MapData<K, V> map(Generator<K> genK, V value, int quantity) {return new MapData<K, V>(genK, value, quantity);}public static <K, V> MapData<K, V> map(Iterable<K> genK, Generator<V> genV) {return new MapData<K, V>(genK, genV);}public static <K, V> MapData<K, V> map(Iterable<K> genK, V value) {return new MapData<K, V>(genK, value);}
}

这给了你一个机会,去选择使用单一的Generator<Pair<K,V>>、两个分离的Generator、一个Generator和一个常量值、一个Iterable(包括任何Collection)和一个Generator,还是一个Iterable和一个单一值。泛型便利方法可以减少任何在创建MapData类时所必需的类型检查数量。

下面是一个使用MapData的示例。LettersGenerator通过产生一个Iterator还实现了Iterable,通过这种方式,它可以被用来测试MapData.map()方法,而这些方法都需要用到Iterable:

import java.util.Iterator;import com.buba.util.CountingGenerator;
import com.buba.util.Generator;
import com.buba.util.MapData;
import com.buba.util.Pair;
import com.buba.util.RandomGenerator;class Letters implements Generator<Pair<Integer, String>>, Iterable<Integer> {private int size = 9;private int number = 1;private char letter = 'A';@Overridepublic Iterator<Integer> iterator() {return new Iterator<Integer>() {@Overridepublic boolean hasNext() {return number < size;}@Overridepublic Integer next() {return number++;}};}@Overridepublic Pair<Integer, String> next() {return new Pair<Integer, String>(number++, "" + letter++);}
}public class MapDataTest {public static void main(String[] args) {System.out.println(MapData.map(new Letters(), 11));System.out.println(MapData.map(new CountingGenerator.Character(), new RandomGenerator.String(3), 8));System.out.println(MapData.map(new CountingGenerator.Character(), "Value", 6));System.out.println(MapData.map(new Letters(), new RandomGenerator.String(3)));System.out.println(MapData.map(new Letters(), "Pop"));}
}

可以使用工具来创建任何用于Map或Collection的生成数据集,然后通过构造器或Map.putAll()和Collection.addAll()方法来初始化Map和Collection。

如果本文对您有很大的帮助,还请点赞关注一下。

容器深入研究(1):完整的容器分类法、填充容器(上)相关推荐

  1. Java编程思想笔记——容器深入研究1

    完整的容器分类法 Java SE5新添加了: 1.Queue接口(LinkedList已经为实现该接口做了修改)及其实现PriorityQueue和各种风格的BlockingQueue. 2.Conc ...

  2. think-in-java(17)容器深入研究

    注意: 17章接着 11章继续分析 java容器, think-in-java(11) [17.1]完整的容器分类方法 [容器分类网络解说] 1)接口:虚线框,没有实线入边(没有实体类继承关系,只有接 ...

  3. PPTV之大数据集群容器化研究

    本文讲的是PPTV之大数据集群容器化研究[编者的话]如何统一调度两个集群的物理资源,有效节约成本? 背景 PPTV作为国内视频领域的领先者,对于大规模流媒体的存储.处理.分发及应用,有着迫切的要求.容 ...

  4. 揭开容器的神秘面纱:帮助初学者深入了解容器技术

    戳蓝字"CSDN云计算"关注我们哦! 本文转载自:Docker  简介 无论你是学生,还是公司的开发人员,或是软件爱好者,相信你都听说过容器. 你可能还听说容器是轻量级虚拟机,但这 ...

  5. vm 和 容器对比_您将VM放在我的容器中

    vm 和 容器对比 史蒂夫·戈登(Steve Gordon)撰写了这篇文章. 容器和Kubernetes已被广泛推广为"破坏性"技术,它将取代它们之前的所有内容,最著名的是虚拟机( ...

  6. docker切换到linux容器模式,linux – 将虚拟主机转换到Docker容器

    我目前在Plesk上运行一个Red Hat Linux服务器来托管一百个域名.由于多种原因,我想从每个虚拟主机作为一个或多个容器过渡到Plesk和Docker容器.到目前为止,我还不清楚这是最好的方法 ...

  7. Docker容器化实战第三课 dockerfile介绍、容器安全与监控讲解

    06 最佳实践:如何在生产中编写最优 Dockerfile? 在介绍 Dockerfile 最佳实践前,这里再强调一下,生产实践中一定优先使用 Dockerfile 的方式构建镜像. 因为使用 Doc ...

  8. Docker容器-------网络模式,数据卷和数据卷容器

    目录 Docker网络实现原理 Docker的网络模式 Host模式 Container模式 none模式 bridge模式 自定义网络 查看网络模式列表 查看容器信息(包含配置.环境.网关.挂载.c ...

  9. 2021年R1快开门式压力容器操作最新解析及R1快开门式压力容器操作证考试

    题库来源:安全生产模拟考试一点通公众号小程序 安全生产模拟考试一点通:R1快开门式压力容器操作最新解析是安全生产模拟考试一点通总题库中生成的一套R1快开门式压力容器操作证考试,安全生产模拟考试一点通上 ...

最新文章

  1. [CTO札记]互联网一定要免费吗?网络文学是继网络游戏后又一成功的收费模式...
  2. 【网络安全】JAVA代码审计—— XXE外部实体注入
  3. 【机器学习】如何通俗易懂地阐述机器学习?
  4. xtrabackup周全备+增备Python脚本
  5. MySQL 7种日志类型 详解
  6. redis存储新闻列表_Redis对象——集合(Set)
  7. imagick用法!
  8. C#设计学生成绩排序
  9. 心情随笔(三):注入新的血液
  10. _tcstoul() 使用
  11. ActivityMq下载、安装、使用
  12. windows切换桌面的快捷键
  13. 【转载】如何成为优秀的网络安全工程师
  14. 高斯-勒让德求积公式及Matlab实现
  15. mongodb类型转换
  16. 华为“鸿蒙”所涉及的微内核到底是什么?一文带你认识微内核
  17. Vue进阶(四十四):vue 图片加载完成事件
  18. swp安装(Scientific Work Place)
  19. IntelliJ IDEA 在方法大括号中{}点击回车多出一个},如何取消
  20. 佐治亚州立大学计算机科学,佐治亚州立大学计算机科学研究生语言及申请要求-费用-课程设置...

热门文章

  1. 【案例】蜂巢链:基于区块链的资产证劵化
  2. 022减淡工具,加深工具与海绵工具
  3. idea简便导入jar包的方法
  4. 基于Python高校图书馆图书管理系统的设计与实现(PyCharm,MySQL)
  5. 数据库-MySQL-基础(2)-DDL操作
  6. 在Discuz论坛安装出现乱码时
  7. 【Android技巧】通过am完成发送开机广播等操作
  8. Linux系统中more和less命令的区别
  9. 强化学习实例5:构建简单蛇棋环境
  10. python爬虫爬出新高度