集合
1.父接口:Collection
java.util.Collection 是进行单对象保存的最大父接口,即每次利用 Collection 接口都只能保存一个对象信息。定义如下:
代码语言:javascript复制public interface Collection<E> extends Iterable<E> {}
Collection 接口中使用了泛型,可以保证集合中操作数据类型的统一,同时 Collection 接口属于 Iterator 的子接口。
常用方法:
方法名称 | 方法描述 |
---|---|
public boolean add(E e) | 向集合里面保存数据 |
public boolean addAll(Collection<? extends E> c) | 追加一个集合 |
public void clear() | 清除集合,根元素为 null |
public boolean contains(Object o) | 判断是否包含指定的内容,需要 equals() 支持 |
public boolean isEmpty() | 判断是否是空集合 |
public boolean remove(Object o) | 删除对象,需要 equals() 支持 |
public int size() | 取得集合中保存的元素个数 |
public Object[] toArray() | 将集合变为对象数组保存 |
public Iterator iterator() | 为 Iterator 接口实例化 |
缺点:虽然 Collection 是单对象集合操作的最大接口,但是 Collection 接口本身却存在一个问题:无法区分保存的数据是否重复。由此引申出 Collection 的两个子接口:List 接口(数据允许重复)、Set 接口(数据不允许重复)
集合关系:
1.1 List 子接口
List 子接口最大的功能是里面所保存的数据可以存着重复内容,并且在 Collection 子接口中 List 子接口是最为常用的一个子接口,在 List 接口中对 Collection 接口的功能进行了扩充。
常用方法:
方法名称 | 方法描述 |
---|---|
public E get(int index) | 取得索引编号的内容 |
public E set(int index , E element) | 修改指定索引编号的内容 |
public ListIterator< E> listIterator() | 为 ListIterator接口实例化 |
1.1.1 ArrayList 子类
ArrayList 子类是 List 子接口中最为常用的一个子类。
范例:
结果展示:
代码说明:通过 ArrayList 子类实例化了 List 接口对象,这样就可以使用 List 接口中定义的方法(包括 Collection 接口定义的方法),由于 List 接口相对于 Collection 接口中扩充了 get() 方法,可以用循环方式依次取出集合中的每一个保存数据。
1.1.2 Vector 子类(现在少用)
在 JDK 1.0 时就已经提供了 Vector 类。
范例:
这里只是将 ArrayList 子类替换成 Vector 子类,最终都是利用子类实例化 List 接口对象;两个子类最大的区别:Vector 类中的部分方法使用 synchronized 关键字声明。
1.2 Set 子接口
Set 子接口并不像 List 子接口那样对 Collection 接口进行了大量的扩充,而是简单地继承了 Collection 接口。就是说在 Set 子接口里面无法使用 get() 方法根据索引取得保存数据的操作。Set 子接口有两个常用的子类:HashSet、TreeSet。 HashSet 是散列存放数据(HashMap),而 TreeSet 是有序存放的子类。
1.2.1 HashSet 子类
HashSet 子类实例化了 Set 接口对象,并且在 Set 集合中不允许保存重复数据。
范例:
结果展示:
由上例子我们可以看出,重复元素是不允许保存的,并且元素是无序的。
扩展: HashSet 采用了 Hash 算法(散列、无序)。该算法就是利用二进制的计算结果来设置保存的空间,根据数值的不同,最终保存空间的位置也不同,所有利用 Hash 算法保存的集合都是无序的,但是其查找速度较快。
1.2.2 TreeSet 子类
如果希望保存的数据有序,那么可以使用 Set 接口的另外一个子类:TreeSet 子类。
范例:
结果展示:
由上例子我们可以看出,重复元素是不允许保存的,但是元素是有序的,默认情况下按照字母的升序排列。
2. 集合输出
一般集合中保存多个对象数据,需要进行集合输出时都会采用循环的方式完成。集合的输出操作有 4 种形式:Iterator 输出、ListIterator 输出、foreach(加强型 for 循环)、Enumeration 输出。
2.1 迭代输出:Iterator
集合输出操作中最为常用的接口,而在 Collection 接口中也提供了直接为 Iterator 接口实例化的方法( iterator() ),所以任何集合类型都可以转换为 Iterator 接口输出。在 Iterator 接口中一共定义了两个抽象方法
抽象方法:
方法名称 | 方法描述 |
---|---|
public boolean hasNext() | 判断是否还有内容 |
public E next() | 取出当前内容 |
当使用 Iterator 接口输出时,往往都先利用 hasNext() 改变指针位置,同时判断是否有数据,如果当前指针所在位置存在数据,则利用 next() 取出数据,这两个方法的作用如下图:
范例:
利用 List 接口的 iterator() 方法将全部集合转变成为 Iterator 输出,由于不确定循环次数,所有使用 while 循环进行迭代输出。
2.2 双向迭代:ListIterator
为了让输出变得更加灵活,在类集框架中就提供了一个 ListIterator 接口,利用此接口可以实现双向迭代。
常用方法:
方法名称 | 方法描述 |
---|---|
public boolean hasPrevious() | 判断是否有前一个元素 |
public E previous() | 取出前一个元素 |
public void add(E e) | 向集合追加数据 |
public void set(E e) | 修改集合数据 |
在 listIterator 接口中除了可以继续使用Iterator 接口的hasNext() 与 next() 方法,也具备了向前迭代的操作(hasPrevious()、previous() ),同时还提供了向集合追加数据和修改数据的支持。注意:ListIterator 如果要进行由后向前迭代,必须先进行由前向后迭代。
范例
结果展示:
使用 ListIterator 接口实现了 ListIterator 集合的双向迭代输出,首先利用 hasNext() 与 next() 实现由前向后的数据迭代,然后使用 hasPrevious() 与 previou() 两个方法实现了数据的由后向前迭代。
2.3 foreach 输出
JDK 1.5 之后为了简化数组以及集合的输出操作,专门提供了 foreach 输出。
foreach 格式: for (数据类型 变量 : 数组 / 集合)
范例
结果展示:
由于集合中保存的都是 String 型数据,所以每次执行 foreach 循环时,都会将当前对象内容赋值给 str 对象,而后就可以在循环体中利用 str 对象进行操作。
2.4 Enumeration 输出
Enumeration(枚举输出)是与 Vector 类一起在 JDK 1.0 时推出的输出接口,即最早的 Vector 如果要输出数据,就需要使用 Enumeration 接口完成,接口定义如下:
代码语言:javascript复制public interface Enumeration< E>{
public boolean hasMoreElements(); // 判断是否有下一个元素,等同于 hasNext()
public E nextElement(); // 取出当前元素,等同于 next()
}
范例:
结果展示:
如果要利用集合类为 Enumeration 接口实例化,就必须依靠 Vector 子类完成。
3. 偶对象保存:Map接口
Collection 每次只能保存一个对象,所以属于单值保存父接口。而在类集中又提供了保存偶对象的集合:Map 集合,利用 Map 结合可以保存一对关联数据(key=value),如下图所示,这样就可以实现根据 key 取得 value 的操作。
常用方法:
方法名称 | 方法描述 |
---|---|
public V put(K key,V value) | 向集合中保存数据 |
public V get(Object key) | 根据 key 查找对应的 value 数据 |
public Set<Map.Entry<K,V>> entrySet() | 将 Map 集合转化为 Set 集合 |
public Set< K > keySet() | 取出全部的 key |
3.1 HashMap 子类
HashMap 子类的使用
结果展示:
本程序实现了 Map 最为基础的数据保存操作,在实例化 Map 接口对象时首先需要明确地指定泛型类型,此处指定 key 的类型为 String,value 的类型为 Integer,然后利用 put() 方法进行数据的保存。**特别注意的是,在进行数据保存时,如果出现了 key 重复的情况,就会使用新的数据替换已有的数据;Map 集合是无序存放的;保存数据时 key 或 value 可以保存为 null;**其次,利用 Map 接口中的 get() 方法根据 key 取得了其对应的 value 内容,如果指定的 key 存在则返回对应的 value,不存在 key 则返回 null
特别注意
HashMap 的 key-value 支持 key-value,null-null,key-null,null-value 四种。 而 Hashtable 只支持 key-value 一种(即 key 和 value 都不为 null 这种形式)。 既然 HashMap 支持带有 null 的形式,那么在 HashMap 中不能由 get() 方法来判断 HashMap 中是否存在某个键, 而应该用 containsKey() 方法来判断, 因为使用 get 的时候,当返回 null 时,你无法判断到底是不存在这个 key ,还是这个 key 就是 null ,还是 key 存在但 value 是 null 。
3.2 Hashtable 子类
JDK 1.0 时提供的,属于最早的 Map 集合的实现操作。是线程安全的类,在使用 Hashtable 子类实例化的 Map 集合中,保存的 key 或 value 都不允许出现 null,否则会出现 “NullPointerException” 异常。
由于代码跟 HashMap 相类似,这里就不再详述了。
3.3 利用 Iterator 输出 Map 集合
集合的输出要利用 Iterator 接口完成。但是 Map 接口与 Collection 接口在定义上有所不同,Map 接口并没有提供直接取得 Iterator 接口对象的方法。Collection 集合保存数据时所有的对象都是直接保存的。而用 Map 集合保存数据时,所保存的 key 与 value 会自动包装为 Map.Entry 接口对象,也就是说如果利用 Iterator 进行迭代,那么每当使用 next() 方法读取数据时返回的都是一个 Map.Entry 接口对象。此接口定义如下。
代码语言:javascript复制public static interface Map.Entry<K,V> {}
Map.Entry 接口属于 Map 接口中定义的一个 static 内部接口(相当于外部接口)
常用方法:
方法名称 | 方法描述 |
---|---|
public K getKey() | 取得数据中的 key |
public V getValue() | 取得数据中的 value |
public V setValue(V value) | 修改数据中的 value |
清楚了 Map.Entry 接口作用后就可以来研究如何利用 Iterator 接口输出 Map 集合了,在 Map 接口中定义了一个 entrySet() 方法
代码语言:javascript复制public Set<Map.Entry<K,V>> entry())
而实现 Map 接口输出的关键就在于此方法的使用上。
Iterator 输出 Map 集合的 操作步骤 如下。
1. 利用 entrySet() 方法将 Map 接口数据中的数据转换成为 Set 接口实例进行保存,此时 Set 接口中所使用的泛型类型为 Map.Entry ,而 Map.Entry 中的 K 与 V 的泛型类型则与 Map 集合定义的 K 与 V 类型相同; 2. 利用 Set 接口中的 iterator() 方法将 Set() 集合转化为 Iterator 接口实例。 3. 利用 Iterator 接口进行迭代输出,每一次迭代取得的都是 Map.Entry 接口实例,利用此接口实例可以进行 key 与 value 的分离。
范例:
结果展示:
本程序实现了 Iterator 接口输出 Map 集合的操作,最为关键的就是 Iterator 每次迭代返回的类型是 Map.Entry(注意泛型类型的设置),而后利用 getKey() 与 getValue() 方法才可以取得所保存的 key 与 value 数据。
4. Stack 子类
栈是一种 动态对象数组,采用的是一种 先进先出 的数据结构形式,即在栈中最早保存的数据最后才会取出,而最后保存的数据可以最先取出。
在 java.util 包中可以利用 Stack 类实现栈的功能,代码如下
代码语言:javascript复制public class Stack <E> extends Vector<E>
通过代码可知, Stack 类属于 Vector 子类,但需要注意的是,在进行 Stack 操作时不会使用 Vector 类的定义的方法,主要使用 Stack 类定义的方法。
常用方法:
方法名称 | 方法描述 |
---|---|
public E push(E item) | 数据入栈 |
public E pop() | 数据出栈,如果栈中没有数据,调用该方法会抛出空栈异常(EmptyStackException) |
范例
结果展示:
5. Properties 子类
利用 Map 集合可以将任意的数据类型设置为 key 或 value 的类型,虽然这样较为灵活,但是在某些开发中并不适用,所有在类集框架中提供了一个 Properties 子类,利用此子类只能保存字符串类型的数据(key=value)。
Properties 类本身属于 Hashtable 的子类,但是由于 Properties 类都使用 String 数据类型进行操作,所以在使用 Properties 类时主要使用本类所定义的方法。
常用方法:
方法名称 | 方法描述 |
---|---|
public Object setProperty(String key,String value) | 设置属性 |
public String getProperty(String key) | 取得属性,如果 key 不存在则返回 null |
public String getProperty(String key,String defaultValue) | 取得属性,如果 key 不存在则返回 默认值 |
public void store(OutputStream out,String comments) throws IOException | 通过输出流保存属性内容,输出的同时可以设置注释信息 |
public void load(InputStream in) throws IOException | 通过输入流读取属性内容 |
范例
** 结果展示:**
6. Collections 工具类
Collections 这个工具类实现可以实现 List、Set、Map 集合的操作。
常用方法
方法名称 | 方法描述 |
---|---|
public static < T > boolean addAll(Collection<? super T> c,T … elements) | 实现集合数据追加 |
public static < T > int binarySearch(List<? extends Comparable<? super T>> list,T key) | 使用二分查找法查找集合数据 |
public static < T > void copy(List <? super T> dest,List<? extends T> src) | 集合复制 |
public static void reverse(List<?> list) | 集合反转 |
public static < T extends Comparable<? super T>> void sort(List< T> list) | 集合排序 |
结果展示
首先实例化一个空的集合对象,然后利用 Collections 类的addAll() 方法一次性向集合中追加了多条数据,最后又利用 reverse() 方法实现了集合数据的反转操作。
总结
- 类集的目的是创建动 态的对象数组操作。
- Collection 接口是类集中最大单值操作的父接口,但是一般开发中不会直成使用此接口, 而常使用 List 或 Set 接口。
- List接口扩展了Collection接口,里面的内容是允许重复的。
- List 接口的常用子类是 ArrayList 和 Vector。在开发中 ArrayList 性能较高,属于异步处理;而Vector性能较低,属于同步处理。
- Set 接口写 Collection 接口的定义一致,里面的内容不允许重复,依靠 Object 类中的 equals() 和 hashCode() 方法来区分是否是同一个对象。
- Set 接口的常用子类是 HashSet 和 TreeSet。HashSet 是散列存放,没有顺序;TrreSet 是顺序存放,使用 Comparable 进行排序操作。
- 集合的输出要使用 Iterator 接口完成,Iterator 属于迭代输出接口。
- 在 JDK 1.5 之后集合也可以使用 foreach 的方式输出。
- Enumeration 属于最早的迭代输出接口,现在基本上很少使用,在类集中 Vector 类可以使用 Enumeration 接口进行内容的输出。
- List 集合的操作可以使用 ListIterator 接口进行双向的输出操作。
- Map 接口可以存放一对内容,所有的内容以 “key = value” 的形式保存,每一对 "key = value ” 都是一个Map. Entry对象的实例。
- Map 中的常用子类是HashMap. Hastable HashMlap 属于异步处理,性能较高: Hese |同步处理,性能较低。