Java中有一些对象被称为容器(container)。容器中可以包含多个对象,每个对象称为容器中的一个元素。容器是用对象封装的数据结构(data structure)。

充满梦想的容器

不同的数据结构有不同的组织元素的方式,也可以有不同的操作。根据具体实施的不同,数据结构的操作效率也各有差别。Java中的容器也是这样。我们要选择适当的容器,以应对变化的需求。

(关于数据结构更多的内容,可参考纸上谈兵: 算法与数据结构)

数组

数组(array)是最常见的数据结构。数组是相同类型元素的有序集合,并有固定的大小(可容纳固定数目的元素)。数组可以根据下标(index)来随机存取(random access)元素。在内存中,数组通常是一段连续的存储单元。

Java支持数组这一数据结构。我们需要说明每个数组的类型和大小。如下:

 
public class Test
{
public static void main(String[] args)
{
Human[] persons = new Human[2]; // array size 2
persons[0] = new Human(160);
persons[1] = new Human(170); int[] a = {1, 2, 3, 7, 9}; // array size 5
System.out.println(a[2]); String[] names = {"Tom", "Jerry", "Luffy"}; // array size 3
System.out.println(names[0]);
}
}
 

在说明类型时,在类型说明(Human)后面增加一个[],来说明是一个数组。使用new创建容器时,需要说明数组的大小。

我们可以使用 数组名[下标] 的方式来调用某个元素。我们可以逐个的初始化数组的元素,也可以在声明的同时使用{}初始化数组。

对于非基本类型的数组,比如Human[],数组中存储的是对象的引用。

我们可以调用System.arraycopy()方法来有效的复制数组:

 
public class Test
{
public static void main(String[] args)
{
int[] aFrom = {1, 2, 3, 7, 9}; // array size 5
int[] aTo = new int[3];
System.arraycopy(aFrom, 1, aTo, 0, 3);
System.out.println(aTo[1]);
}
}
 

System.arraycopy()中,aFrom为想要复制出去的数组,aTo为想要复制到的数组,1为aFrom的想要复制出去的元素起始位置,0为aTo中想要存储复制来元素的起始位置,3为所要复制的元素总数。

Collection

表(List)和集合(Set)是java.util中定义的两个接口(interface)。这两个接口都继承自Collection接口。通过实施接口,我们可以获得相应的容器。

我们之前都是使用类(class)来说明引用的类型。事实上,我们也可以用接口(interface)来说明引用的类型。该类型引用所指向的对象必须实施了该接口。

我们先来使用表(List)容器。List是有序的元素集合,所以可以使用下标来说明元素的位置。集合中的元素可以相等:

 
import java.util.*;

public class Test
{
public static void main(String[] args)
{
List<String> l1 = new ArrayList<String>();
l1.add("good");
l1.add("bad");
l1.add("shit");
l1.remove(0);
System.out.println(l1.get(1));
System.out.println(l1.size());
}
}
 

当我们在定义接口和创建容器时,我们使用<class>的方式来说明容器中所能容纳元素的类型。我们将只能在容器中放入class类及其衍生类的对象。

容器的引用为List类型,但容器的实施为ArrayList类。这里是将接口与实施分离。事实上,同一种抽象数据结构(ADT)都可以有多种实施方法(比如栈可以实施为数组和链表)。这样的分离允许我们更自由的选择ADT的实施方式。

我们可以定义<Object>类型的容器。由于Java中的所有类都继承自Object类,这样的容器实际上可以放入任意类型的对象。

在上面的程序中,容器为String类型。我们用

  • add()方法加入新的元素
  • get()方法可以获取容器中的元素,传递一个整数下标作为参数
  • remove()方法可以删除容器中的元素,传递一个整数下标作为参数。(有另一个remove(),传递元素自身作为参数)
  • size()方法用来返回容器中元素的总数。

List的官方文档

集合(set)也是元素的集合。集合中不允许有等值的元素,集合的元素没有顺序:

 
import java.util.*;

public class Test
{
public static void main(String[] args)
{
Set<Integer> s1 = new HashSet<Integer>();
s1.add(4);
s1.add(5);
s1.add(4);
s1.remove(5);
System.out.println(s1);
System.out.println(s1.size());
}
}
 

重复加入的元素4只被放入容器一次。由于Set是无序的,在remove()中,我们直接传递目标元素本身作为参数。

Set的官方文档

List和Set都继承自Collection接口。Collection代表了对象的集合。上面List和Set接口中的许多方法实际上继承自Collection,比如:

add("good")        加入元素

size()             返回元素的总数

contains("bad")    是否包含元素

remove("good")     删除元素

Collection的官方文档

Collection还有一个iterator()的方法。该方法将Collection容器封装成循环器(Iterator)。循环器是元素的集合,它有next()方法,用于每次返回一个元素,直到循环器中元素穷尽。

 
import java.util.*;

public class Test
{
public static void main(String[] args)
{
List<Integer> l1 = new ArrayList<Integer>();
l1.add(4);
l1.add(5);
l1.add(2);
Iterator i = l1.iterator();
while(i.hasNext()) {
System.out.println(i.next());
}
}
}
 

Iterator的官方文档

Map

Map是键值对的集合。Map中的每个元素是一个键值对,即一个键(key)和它对应的对象值(value)。对于Map容器,我们可以通过键来找到对应的对象。

哈希表是Map常见的一种实施方式,参考纸上谈兵: 哈希表 (hash table)

我们需要声明Map的键和值的类型。我们下面实施一个HashMap:

 
import java.util.*;

public class Test
{
public static void main(String[] args)
{
Map<String, Integer> m1 = new HashMap<String, Integer>();
m1.put("Vamei", 12);
m1.put("Jerry", 5);
m1.put("Tom", 18);
System.out.println(m1.get("Vamei")); }
}
 

在Map中,我们使用put()方法来添加元素,用get()方法来获得元素。

Map还提供了下面的方法,来返回一个Collection:

keySet()  将所有的键转换为Set

values()  将所有的值转换为List

总结

Java中,容器的接口与实施分离。这给了Java程序员更大的选择自由,当然,也为编程增加了难度。

接口为我们提供了合法的操作。在效果层面上看,不同的实施都有相同的效果。当然,不同的情境下,实施的细节将决定运行效率。

最后,是我们提到的各个类与接口的关系:

Java进阶06 容器的更多相关文章

  1. java进阶视频分享

    更多资源和教程请关注公众号:非科班的科班. 如果觉得我写的还可以请给个赞,谢谢大家,你的鼓励是我创作的动力 课程目录介绍 01.开班仪式02.并发编程专题之多线程基础03.并发编程专题之Java内存模 ...

  2. Java进阶(三)多线程开发关键技术

    原创文章,同步发自作者个人博客,转载请务必以超链接形式在文章开头处注明出处http://www.jasongj.com/java/multi_thread/. sleep和wait到底什么区别 其实这 ...

  3. Java进阶(三十五)java int与integer的区别

    Java进阶(三十五)java int与Integer的区别 前言 int与Integer的区别从大的方面来说就是基本数据类型与其包装类的区别: int 是基本类型,直接存数值,而Integer是对象 ...

  4. Java进阶(五十二)利用LOG4J生成服务日志

    Java进阶(五十二)利用LOG4J生成服务日志 前言 由于论文写作需求,需要进行流程挖掘.前提是需要有真实的事件日志数据.真实的事件日志数据可以用来发现.监控和提升业务流程. 为了获得真实的事件日志 ...

  5. java 从spring容器中获取注入的bean对象

      java 从spring容器中获取注入的bean对象 CreateTime--2018年6月1日10点22分 Author:Marydon 1.使用场景 控制层调用业务层时,控制层需要拿到业务层在 ...

  6. Java进阶资料汇总

    Java经过将近20年的发展壮大,框架体系已经丰满俱全:从前端到后台到数据库,从智能终端到大数据都能看到Java的身影,个人感觉做后台进要求越来越高,越来越难. 为什么现在Java程序员越来越难做,一 ...

  7. (转)Java进阶java int与Integer的区别

    Java进阶java int与Integer的区别 前言 int与Integer的区别从大的方面来说就是基本数据类型与其包装类的区别: int 是基本类型,直接存数值,而Integer是对象,用一个引 ...

  8. 大型Java进阶专题(一) 前言

    前言 ​ 各位读者好,本系列为Java进阶专题,为那些有一定工作经验,做了多年业务的码农,希望突破技术瓶颈,但没有形成系统的Java只是体系,缺乏清晰的提升方法和学习路径的人,比如作者本人.该课题的是 ...

  9. Java 进阶 hello world! - 中级程序员之路

    Java 进阶 hello world! - 中级程序员之路 Java是一种跨平台的语言,号称:"一次编写,到处运行",在世界编程语言排行榜中稳居第二名(TIOBE index). ...

随机推荐

  1. 谷歌浏览器console.log()失效,打印不出来内容

    这个问题困扰好几天了,网上说的都说的是下图: 勾选这三个就好了,但是我的本来就是勾选上的,还是不行. 后来发现这个: 把这个去掉就可以了,如下图: 原来是因为之前调试js的时候,使用了这个过滤,导致对 ...

  2. html5小趣味知识点系列(一)autofocus

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  3. ios cocoapods获取不到最新库的原因主要有两个:

    获取不到最新库的原因主要有两个: 1.cocoapods的版本过低 2.还没有更新本地仓库 解决方法: 1.更新pods 在终端执行命令行 sudo gem install cocoapods 执行完 ...

  4. byte[] 、Bitmap与Drawbale 三者直接的转换

    经常遇到这种类似头疼的问题 byte[] .Bitmap与Drawbale 三者直接的转换 1.byte[] ->Bitmap Bitmap Bitmap = BitmapFactory.dec ...

  5. 【问题解决】Tomcat 启动时闪退或提示“Neither the JAVA_HOME or the JRE_HOME environmental variable is defined.”

    问题解决思路: 1.分析startup.bat启动脚本:发现其调用了catalina.bat,而catalina.bat调用了setclasspath.bat 2.在setclasspath.bat的 ...

  6. K.Bro Sorting(思维题)

    K.Bro Sorting Time Limit: 2000/2000 MS (Java/Others)    Memory Limit: 512000/512000 K (Java/Others)T ...

  7. java web Listener的简单使用案例

    1.web.xml的配置 <?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi= ...

  8. mybatis相关

    1 namespace dao中使用namespace+id一起来完成对mapper中sql statement的调用. 2 关于resultMap和parameterType parameterTy ...

  9. LLVM编译器

    LLVM 1. 说说 LLVM(Low Level Virtual Machine)到底是什么吧 先说编译器:编译器是把程序员的代码翻译成机器可以理解的语言的工具: 再谈 LLVM:一个模块化和可重用 ...

  10. spring bean实例化的三种方式

    一.使用类的无参构造创建 配置文件 java代码 注意若类里面没有无参的构造,则会出现异常 二.使用静态工厂创建 配置文件 java代码 Factory类 测试类 结果 三.使用实例工厂 配置文件 1 ...