Java 类集框架
来源:互联网 发布:淘宝卖家如何借贷 编辑:程序博客网 时间:2024/05/17 19:17
概念
类集是一种动态的对象数组,属于各个数据结构的实现类,整个类集的主要组成是一些核心的操作接口:Collection,List,Set,Map,Iterator和Enumeration.以下是部分类集框架的继承结构图:
注:
单值保存
Collection接口
所谓单值保存指的是每一次操作只会保存一个对象.单值保存的最大父类是Collection.在Collection接口中定义了如下的一些常用方法:
一般在开发中很少会直接使用Collection接口,一般会使用它的两个子接口:List和Set.
List接口
List接口是Collection的一个最为常用的允许重复的子接口,此接口的定义如下:
public interface List<E>extends Collection<E>
虽然List接口直接继承了Collection接口,但是List接口对Collection接口进行了大量的扩充,扩充后的主要方法如下:
List接口有两个常用的子类:
- ArrayList
- Vector
ArrayList
ArrayList是List接口中使用最多的一个子类.按照面向对象的概念,使用ArrayList的主要目的是为List接口实例化,而所有的操作方法都以List接口中定义的为主.
代码示例
import java.util.List;import java.util.ArrayList;public class TestDemo{ public static void main(String [] args){ // 实例化List接口 List<String> list = new ArrayList<String>(); // 往集合中添加数据 list.add("Hello"); list.add("World"); list.add("Hello"); System.out.println(list); }}
程序运行结果
[Hello, World, Hello]
通过本程序可以发现,List集合中即使存在了重复数据,也可以正常保存,而且数据保存的顺序是存入数据的顺序.
Vector
Vector类是在JDK1.0时就推出的一个实现动态数组的操作类,相对于ArrayList是一个旧的子类.与ArrayList的使用类似.
代码示例
import java.util.List;import java.util.ArrayList;public class TestDemo{ public static void main(String [] args){ // 实例化List接口 List<String> list = new Vector<String>(); // 往集合中添加数据 list.add("Hello"); list.add("World"); list.add("Hello"); System.out.println(list); }}
程序运行结果
[Hello, World, Hello]
本程序的运行结果和使用ArratLis子类的程序没有任何区别,唯一不同的地方就是使用Vector子类完成List接口的实例化,但是由于所有的操作都是针对接口完成的,只要接口定义的方法不变,子类可以随意更改.
ArrayList和Vector的区别
Set接口
Set接口也是Collection接口常用的不允许重复的子接口,此接口的定义如下:
public interface Set<E> extends Collection<E>
Set接口也是直接继承了Collection接口,但是与List接口不同.Set接口只是完整的继承了Collection接口,而没有进行任何方法的扩充.所以Set子类接口中肯定无法使用get()方法取得指定索引的数据.Set接口常用的两个子类:
- HahSet
- TreeSet
散列排放的子类
HashSet使用一种散列(无序)的方式保存集合数据.
代码示例
import java.util.HashSet;import java.util.Set;public class TestDemo{ public static void main(String [] args){ // 实例化Set接口 Set<String> set = new HashSet<String>(); // 往set中添加数据 set.add("January"); set.add("February"); set.add("March"); set.add("February"); System.out.println(set); }}
程序运行结果
[March, January, February]
通过本程序可以发现:使用Set集合保存数据时,集合还总重复的数据并没有被保存,并且保存的数据也是无序的(不是按输入顺序保存)
排序排放的子类
HashSet使用一种排序的方式保存集合数据.
代码示例
import java.util.Set;import java.util.TreeSet;public class TestDemo{ public static void main(String [] args){ // 实例化Set接口 Set<String> set = new TreeSet<String>(); // 往set中添加数据 set.add("January"); set.add("February"); set.add("March"); set.add("February"); System.out.println(set); }}
程序运行结果
[February, January, March]
此时程序只是更换一个Set接口的子类,运行之后,集合中没有重复数据,并且按照数据的大小排序.
重复元素和TreeSet排序的说明
- 在使用TreeSet实例化Set接口时保存自定义类的对象数据时,要正确排序自定义对象的大小,那么对象所在的类必须实现Comparable接口,设置比较规则.需要注意的是:
一旦使用了Comparable后,类中的所有属性都必须写进排序规则
代码示例
import java.util.Set;import java.util.TreeSet;class Person implements Comparable<Person>{ private String name; private int age; public Person(){} public Person(String name, int age){ this.name = name; this.age = age; } @Override public String toString(){ return "姓名:" + this.name + ",年龄:" + this.age + "\n"; } @Override public int compareTo(Person per){ if(this.age != per.age){ return per.age > this.age?1:0; } else{ if(!per.name.equals(this.name)){ return per.name.compareTo(this.name); } else{ return 0; } } }}public class TestDemo{ public static void main(String [] args){ Set<Person> set = new TreeSet<Person>(); set.add(new Person("张三", 20)); set.add(new Person("王五", 19)); set.add(new Person("李四", 20)); set.add(new Person("赵六", 18)); set.add(new Person("张三", 20)); System.out.println(set); }}
程序运行结果
[姓名:李四,年龄:20
, 姓名:张三,年龄:20
, 姓名:王五,年龄:19
, 姓名:赵六,年龄:18
]
在此程序中,Person类实现了Comparable接口,所以Set集合中可以正确的进行排序(由年龄从大到小排序,年龄相同再根据姓名排序),而对于重复的数据,由于通过compareTo()方法比较后的结果为0,所以就不再进行保存.所以有一个结论:
- 虽然TreeSet可以依靠Comparable进行重复元素判断,但是HashSet子类却无法依靠Comparable接口进行重复元素判断.实际上所有重复元素的判断依赖于Object类的两个方法.
1. hash码:public int hashCode();
2. 对象比较:public boolean equals(Object obj).
这两个方法可以由Eclipse自动生成.
在进行对象的比较过程中,首先会使用hasCode()与已经保存在集合中的对象的hashCode()进行比较,如果代码相同,则在与equals()方法进行属性的依次判断,如果全部相同,则为相同元素.
代码示例
没有实现equals()和hashCode()方法的覆写
import java.util.HashSet;import java.util.Set;class Person{ private String name; private int age; public Person(String name, int age){ this.name = name; this.age = age; } @Override public String toString(){ return "姓名:" + this.name + ", 年龄:" + this.age + "\n"; }}public class TestDemo{ public static void main(String [] args){ Set<Person> set = new HashSet<Person>(); set.add(new Person("张三", 20)); set.add(new Person("李四", 21)); set.add(new Person("王五", 18)); set.add(new Person("张三", 20)); System.out.println(set); }}
程序运行结果
[姓名:王五, 年龄:18
, 姓名:张三, 年龄:20
, 姓名:李四, 年龄:21
, 姓名:张三, 年龄:20
]
此程序没有实现equals()和hashCode()方法的覆写,在HashSet集合中出现重复数据.
实现equals()和hashCode()方法的覆写
import java.util.HashSet;import java.util.Set;class Person{ private String name; private int age; public Person(String name, int age){ this.name = name; this.age = age; } @Override public String toString(){ return "姓名:" + this.name + ", 年龄:" + this.age + "\n"; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + age; result = prime * result + ((name == null) ? 0 : name.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Person other = (Person) obj; if (age != other.age) return false; if (name == null) { if (other.name != null) return false; } else if (!name.equals(other.name)) return false; return true; }}public class TestDemo{ public static void main(String [] args){ Set<Person> set = new HashSet<Person>(); set.add(new Person("张三", 20)); set.add(new Person("李四", 21)); set.add(new Person("王五", 18)); set.add(new Person("张三", 20)); System.out.println(set); }}
程序运行结果
[姓名:李四, 年龄:21
, 姓名:王五, 年龄:18
, 姓名:张三, 年龄:20
]
此程序利用了Object类的equals()和hashCode()方法真正实现了重复元素的判断.
偶对象保存
偶对象指的是一对对象,即两个对象同时保存.这两个对象是按照key = value的形式进行定义的,即可以通过key找到对应的value数据.Map接口就实现这样一个操作的数据结构.
Map接口
Map接口中定义的常用方法
新的子类
代码示例
import java.util.Map;import java.util.Set;import java.util.HashMap;public class TestDemo{ public static void main(String [] args){ Map<String, Integer> map = new HashMap<String, Integer>(); map.put("张三", 19); // 保存数据 map.put(null, null); //key为null map.put("张三", 18); // key重复,value会被新值覆盖 map.put("李四", 19); // 保存数据 map.put("王五", 16); // 保存数据 map.put("赵六", 13); // 保存数据 System.out.println(map.get("张三")); // 取得指定key的数据 Set<String> set = map.keySet(); // 将Map中的所有key以Set集合的方式返回 System.out.println(set); // 输出Set中所有的key值 }}
程序运行接结果
18
[null, 李四, 张三, 王五, 赵六]
本程序使用Map保存数据时设了两个内容(key, value),然后使用get()方法根据指定的key取得对应的value,而且可以发现Map集合中的key不允许重复,若key有重复,其对应的value值会被新值覆盖.接着使用keySet()方法将Map中的所有key以Set的方式返回,并打印.
旧的子类:Hashtable
HashTable是JDK1.0时推出的一种数据结构,相对于HashMap来说是一个比较旧的子类,使用上极为相似,但也存在着区别.
代码示例
import java.util.Map;import java.util.Set;import java.util.Hashtable;public class TestDemo{ public static void main(String [] args){ Map<String, Integer> map = new Hashtable<String, Integer>(); map.put("张三", 19); // 保存数据 map.put("张三", 18); // key重复,value会被新值覆盖 map.put("李四", 19); // 保存数据 map.put("王五", 16); // 保存数据 map.put("赵六", 13); // 保存数据 System.out.println(map.get("张三")); // 取得指定key的数据 Set<String> set = map.keySet(); // 将Map中的所有key以Set集合的方式返回 System.out.println(set); // 输出Set中所有的key值 }}
程序运行结果
18
[赵六, 王五, 张三, 李四]
本程序只是将实例化Map接口的子类替换成了Hashtable类,和将Key值为null 的添加语句删除(Hashtable不能设置key为null)否则运行时会出现”NullPointorException”
HashMap和Hashtable的区别
集合的输出
Java的类集框架中给出了4中输出方式:
- Iterator在Collection接口中定义
- ListIterator在List接口中定义
- Enumeration在Vector子类中定义
- foreachJDK1.5的支持
迭代输出
Iterator是专门迭代输出的接口,所谓的迭代输出就是对元素逐个进行输出,判断其是否有内容,如果有内容则把内容取出.
取得Iterator接口的实例化对象的方法:这一操作在Collection接口中已经明确定义,因为Collection继承了一个Iterator接口,在这个Iterator接口中定义了一个方法”Iterator<E> iterator()
“,所以一般情况下会很少关注Iterator接口,直接使用Collection接口定义的Iterator<E> iterator()
方法即可.
Iterator接口中常用方法
代码示例
import java.util.List;import java.util.Iterator;import java.util.ArrayList;public class TestDemo{ public static void main(String [] args){ List<String> list = new ArrayList<String>(); list.add("Hello"); // 添加数据 list.add("World"); list.add("Hello"); // 使用Iterator输出是数据 Iterator<String> iterator = list.iterator(); while(iterator.hasNext()){ System.out.println(iterator.next()); } }}
程序运行结果
Hello
World
Hello
此程序利用了Iterator接口进行了输出,而对于Collection的所有子接口,都会存在iterator()方法,即Collection接口的所有子接口都支持Iterator接口输出.
双向迭代输出:ListIterator
Iterator接口可以完成由前向后的单向输出操作,要想完成由前向后和由后向前输出需要由Iterator的子接口ListIterator,ListIterator接口主要扩充了以下两个方法:
- public boolean hasPrevious() : 判断是否由前一个元素
- public E previous() : 取出前一个元素
获得ListIterator实例化对象的方法:使用List接口中定义的方法:
public ListIterator<E> listIterator()
代码示例
import java.util.List;import java.util.ArrayList;import java.util.ListIterator;public class TestDemo{ public static void main(String [] args){ // 使用ArrayList子类实例化List接口 List<String> list = new ArrayList<String>(); // 添加数据 list.add("Hello"); list.add("World"); list.add("nihao"); list.add("shijie"); // 取得ListIterator实例化对象 ListIterator<String> iterator = list.listIterator(); // 由前向后输出数据 System.out.println("由前向后迭代输出数据:"); while(iterator.hasNext()){ System.out.println(iterator.next()); } // 由后向前输出数据 System.out.println("由后向前输出数据"); while(iterator.hasPrevious()){ System.out.println(iterator.previous()); } }}
程序运行结果
由前向后迭代输出数据:
Hello
World
nihao
shijie
由后向前输出数据
shijie
nihao
World
Hello
本程序使用ListIterator接口完成数据由前向后迭代输出和由后向前迭代输出.但是需要注意的是:
废弃的接口:Enumeration
Enumeration是一个最早的输出接口,成为枚举输出,在JDK1.0推出,在JDK1.5进行扩充,主要是添加了泛型.获得Enumeration接口的实例化对象:依靠Vector子类中定义的方法完成:
public Enumeration<E> elements()
Enumeration接口中定义的两个方法:
1. public boolean hasMoreElements() : 判断是否有下一个元素
2. public E nextElement() : 取出当前元素
代码示例
import java.util.List;import java.util.Vector;import java.util.Enumeration;public class TestDemo{ public static void main(String [] args){ // 使用Vector子类实例化vector接口 Vector<String> vector = new Vector<String>(); // 添加数据 vector.add("Hello"); vector.add("World"); vector.add("nihao"); vector.add("shijie"); // 取得Enumeration实例化对象 Enumeration<String> iterator = vector.elements(); while(iterator.hasMoreElements()){ System.out.println(iterator.nextElement()); } }}
程序运行结果
Hello
World
nihao
shijie
本程序使用Enumeration接口完成Vector集合数据的迭代输出.但由于Enumeration本身只能通过Vector类对象实例化,所以 在开发中很少使用Enumeration进行开发,优先考虑的是Iterator接口.
JDK1.5的支持:foreach
对于foreach输出,除了可以进行数据数组的内容输出外,也可以针对集合类完成输出.
代码示例
import java.util.List;import java.util.ArrayList;public class TestDemo{ public static void main(String [] args){ // 使用Vector子类实例化list接口 List<String> list = new ArrayList<String>(); // 添加数据 list.add("Hello"); list.add("World"); list.add("nihao"); list.add("shijie"); // 使用foreach完成集合内容的输出 for(String str : list){ System.out.println(str); } }}
程序运行结果
Hello
World
nihao
shijie
本程序使用foreach完成集合内容的输出,代码看起来比较简单,但是还是推荐使用Iterator接口完成集合内容的输出.
Map集合的输出
之前一直在强调:
public static interface Map.Entry<K, V>
很明显,这是一个在Map接口中使用static定义的一个内部接口.Map.Entry接口中定义的两个常用方法:
1. public K getKey() : 取得当前的key
2. public V getValue() : 取得当前的value
下面通过一个图形来对比一下Collection和Map接口保存的数据形式.
通过上图的对比可以发现在Map集合和Collection集合中保存的最大区别是:Collection直接保存的是操作对象,而Map集合是将保存的key和value变成一个Map.Entry对象,通过这个对象包装了key和value.根据这一特性,给出Map使用Iterator输出的操作步骤:
1. 使用Map接口中的entrySet()方法,将Map集合变为Set集合
2. 取得了Set接口实例化后就可以使用iterator()方法取得Iterator的实例化对象
3. 使用Iterator迭代找到每一个Map.Entry对象,并进行key和value的分离.
代码示例
import java.util.HashMap;import java.util.Map;import java.util.Set;import java.util.Iterator;public class TestDemo{ public static void main(String [] args){ // 实例化Map接口 Map<String, Integer> map = new HashMap<String, Integer>(); // 添加数据 map.put("张三", 20); map.put("李四", 23); map.put("王五", 19); map.put("赵六", 21); // 将Map集合变为Set集合 Set<Map.Entry<String, Integer>> set = map.entrySet(); // 使用iterator()方法取得Iterator的实例化对象 Iterator<Map.Entry<String, Integer>> iterator = set.iterator(); // 进行key和value分离 while(iterator.hasNext()){ Map.Entry<String, Integer> me = iterator.next(); System.out.println(me.getKey() + "-->" + me.getValue()); } }}
程序运行结果
李四–>23
张三–>20
王五–>19
赵六–>21
本程序按照之前给出的输出步骤进行代码,完成Map集合数据的输出.
类集转换
- List和Set的相互转换
使用public boolean addAll(Collection<? extends E> c)
方法完成.
Set和Map的相互转换
Map ——> Set
使用
public Set<Map.Entry<K, V>> entrySet()
方法完成将Map转换成Set集合使用
public Set<K> keySet()
方法完成Map集合中的key转换成Set集合
Stack类
栈是采用先进后出的数据存储方式,每一个栈都包含一个栈顶,每次出栈是将栈顶数据取出.
Stack类的常用方法
代码示例
import java.util.Stack;public class TestDemo{ public static void main(String [] args){ Stack<String> s = new Stack<String>(); // 入栈操作 s.push("Hello"); s.push("World"); // 出栈操作 System.out.println(s.pop()); }}
程序运行结果
World
通过程序的运行结果可以发现,出栈的顺序和入栈的顺序正好相反(先进后出).
属性操作类:Properties
属性一般针对于字符串数据,并且所有的字符数据都会按照”key = value”的形式保存,属性操作类主要针对于属性文件完成.
Properties类常用方法
代码示例
- 属性的设置与取得
import java.util.Properties;public class TestDemo{ public static void main(String [] args){ // 构造空的属性类 Properties p = new Properties(); // 保存属性 p.setProperty("张三", "20"); p.setProperty("李四", "21"); p.setProperty("王五", "19"); // 取得属性 System.out.println(p.getProperty("张三")); System.out.println(p.getProperty("李四")); System.out.println(p.getProperty("赵六")); }}
程序运行结果
20
21
null
通过本程序,设置完属性之后,可以利用key查找属性,如果属性不存在便返回null.
- 将属性保存到文件中
import java.io.File;import java.io.FileNotFoundException;import java.io.FileOutputStream;import java.io.IOException;import java.io.OutputStream;import java.util.Properties;public class TestDemo{ public static void main(String [] args) throws IOException{ // 构造空的属性类 Properties p = new Properties(); // 保存属性 p.setProperty("zhangsan", "20"); p.setProperty("lisi", "21"); p.setProperty("wangwu", "19"); // 将属性保存到指定属性文件中 OutputStream out = new FileOutputStream(new File("/home/linyimin/DaSi/java/test.properties")); p.store(out, "Test Info"); }}
程序运行结果
- 通过属性文件读取内容
import java.io.File;import java.io.FileInputStream;import java.io.IOException;import java.io.InputStream;import java.util.Properties;public class TestDemo{ public static void main(String [] args) throws IOException{ // 构造空的属性类 Properties p = new Properties(); // 从指定属性文件中读取属性内容 InputStream in = new FileInputStream(new File("/home/linyimin/DaSi/java/test.properties")); p.load(in); // 读取属性 System.out.println(p.getProperty("zhangsan")); System.out.println(p.getProperty("lisi")); System.out.println(p.getProperty("wangwu")); }}
程序运行结果
20
21
19
本程序从一个已经保存好的资源文件中加载所有的属性内容.除此之外,属性的来源还可能是其他的输入流.
- Java类集框架
- JAVA类集框架
- Java 类集框架
- java 类集框架
- java 类集框架
- JAVA 类集框架
- java类集框架
- Java类集框架
- Java类集框架
- Java类集框架
- Java类集框架
- java类集框架
- Java类集框架
- Java 类集框架
- JAVA类集框架
- java类集框架
- Java类集框架
- Java中的类集框架
- SSH学习之Struts2的环境搭建
- Javascript原型链
- 【模板】常用排序
- c语言程序设计现代方法---第四章:表达式
- git忽略文件和文件夹
- Java 类集框架
- Javascript闭包
- php中的命名空间
- CPU、内存、硬盘、指令
- poj1113(凸包)
- C++11新特性——range for
- Linux c 用栈和队列实现的停车场管理系统
- GC 算法
- Linux~连接windows的ftp,unzip出现的问题