java基础学习——24、容器

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程序员更大的选择自由,当然,也为编程增加了难度。

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

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

时间: 2024-08-04 12:13:01

java基础学习——24、容器的相关文章

Java基础学习--对象容器

要用Java实现记事本的功能.首先列出记事本所需功能: 可以添加记录(字符串): 可以获得记录条数: 可以删除其中某一条记录: 可以获得指定第几条的记录: 可以列出所有的记录. 如果这个记事本是某个大程序的其中一部分,也就是说还有上层程序,那么上层程序就有可能会调用这个记事本以上列出的某个数据. 所以我们称上述多列功能为这个记事本的 接口 . 那么调用这些接口就是通过记事本这个类的public函数(method). 但是,怎么实现记录呢?显然所记录的字符串不能记录在某个数组里,因为数组的长度是预

Java基础学习总结——Java对象的序列化和反序列化

一.序列化和反序列化的概念 把对象转换为字节序列的过程称为对象的序列化. 把字节序列恢复为对象的过程称为对象的反序列化. 对象的序列化主要有两种用途: 1) 把对象的字节序列永久地保存到硬盘上,通常存放在一个文件中: 2) 在网络上传送对象的字节序列. 在很多应用中,需要对某些对象进行序列化,让它们离开内存空间,入住物理硬盘,以便长期保存.比如最常见的是Web服务器中的Session对象,当有 10万用户并发访问,就有可能出现10万个Session对象,内存可能吃不消,于是Web容器就会把一些s

java基础学习总结——GUI编程(一)

永不放弃,一切皆有可能!!! 只为成功找方法,不为失败找借口! java基础学习总结——GUI编程(一) 一.AWT介绍 所有的可以显示出来的图形元素都称为Component,Component代表了所有的可见的图形元素,Component里面有一种比较特殊的图形元素叫Container,Container(容器)在图形界面里面是一种可以容纳其它Component元素的一种容器,Container本身也是一种Component的,Container里面也可以容纳别的Container. Cont

java基础学习总结——GUI编程(二)

永不放弃,一切皆有可能!!! 只为成功找方法,不为失败找借口! java基础学习总结——GUI编程(二) 一.事件监听 测试代码一: 1 package cn.javastudy.summary; 2 3 import java.awt.*; 4 import java.awt.event.*; 5 6 public class TestActionEvent { 7 public static void main(String args[]) { 8 Frame f = new Frame("

java基础学习总结——网络编程

永不放弃,一切皆有可能!!! 只为成功找方法,不为失败找借口! java基础学习总结——网络编程 一.网络基础概念 首先理清一个概念:网络编程 != 网站编程,网络编程现在一般称为TCP/IP编程. 二.网络通信协议及接口 三.通信协议分层思想 四.参考模型 五.IP协议 每个人的电脑都有一个独一无二的IP地址,这样互相通信时就不会传错信息了. IP地址是用一个点来分成四段的,在计算机内部IP地址是用四个字节来表示的,一个字节代表一段,每一个字节代表的数最大只能到达255. 六.TCP协议和UD

java基础学习之 消息对话款

1 package Dome; 2 import java.awt.event.*; 3 import java.awt.*; 4 import javax.swing.*; 5 6 public class WindowMess extends JFrame implements ActionListener 7 { 8 JTextField inputEnglish ; 9 JTextArea show ; 10 String regex = "[a-zZ-Z]+"; 11 Win

java基础学习总结——线程(二)

永不放弃,一切皆有可能!!! 只为成功找方法,不为失败找借口! java基础学习总结——线程(二) 一.线程的优先级别 线程优先级别的使用范例: 1 package cn.galc.test; 2 3 public class TestThread6 { 4 public static void main(String args[]) { 5 MyThread4 t4 = new MyThread4(); 6 MyThread5 t5 = new MyThread5(); 7 Thread t1

java基础学习总结——static关键字

永不放弃,一切皆有可能!!! 只为成功找方法,不为失败找借口! java基础学习总结——static关键字 一.static关键字 原来一个类里面的成员变量,每new一个对象,这个对象就有一份自己的成员变量,因为这些成员变量都不是静态成员变量.对于static成员变量来说,这个成员变量只有一份,而且这一份是这个类所有的对象共享. 1.1.静态成员变量与非静态成员变量的区别 以下面的例子为例说明 1 package cn.galc.test; 2 3 public class Cat { 4 5

java基础学习总结——线程(一)

永不放弃,一切皆有可能!!! 只为成功找方法,不为失败找借口! java基础学习总结——线程(一) 一.线程的基本概念 线程理解:线程是一个程序里面不同的执行路径 每一个分支都叫做一个线程,main()叫做主分支,也叫主线程. 程只是一个静态的概念,机器上的一个.class文件,机器上的一个.exe文件,这个叫做一个 进程.程序的执行过程都是这样的:首先把程序的代码放到内存的代码区里面,代码放到代码区后并没有马上开始执行,但这时候说明了一个进程准备开始,进程已 经产生了,但还没有开始执行,这就是