JavaSE 集合类型详解
集合类型
一、Java集合类型继承关系
引用博客园博主冰湖一角的图片
二、类集接口的介绍
-
Collection
位于类集接口顶层,声明所有类集的核心方法,学习Collection里面的方法很有必要
-
List
List接口是对Collection接口的扩展,可以存储一系列元素,下标基于0;除了拥有Collection定义的方法以外,List还拥有一些自己的方法
对add(int index,Object obj)进行测试
public class Main { public static void main(String[] args) { List list = new ArrayList<>(5); list.add(0,null); list.add(1,'a'); list.add(2,'b'); list.add(3,'c'); list.add(2,'f'); System.out.println(list.toString()); } }//output:[null, a, f, b, c]
对indexOf、lastIndexOf测试
public class Main { public static void main(String[] args) { List list = new ArrayList<>(5); list.add(0,null); list.add(1,'a'); list.add(2,'a'); list.add(3,'a'); list.add(4,'a'); System.out.println(list.indexOf('a')); System.out.println(list.lastIndexOf('a')); } }//output:1 4
对remove进行测试
public class Main { public static void main(String[] args) { List list = new ArrayList<>(5); list.add(0,null); list.add(1,'a'); list.add(2,'b'); list.add(3,'c'); list.add(4,'d'); System.out.println(list.lastIndexOf('d')); list.remove(2); System.out.println(list.lastIndexOf('d')); } }//output:4 3 证明list里面元素是紧凑的,删除元素后会进行压缩
对listIterator进行测试
public static void main(String[] args) { List list = new ArrayList<>(5); list.add(0,null); list.add(1,'a'); list.add(2,'b'); list.add(3,'c'); list.add(4,'d'); ListIterator iterator = list.listIterator(); while (iterator.hasNext()) System.out.print(iterator.next()+","); System.out.println(); System.out.println("=============="); iterator = list.listIterator(2); while (iterator.hasNext()) System.out.print(iterator.next()+","); } //output null,a,b,c,d ============== b,c,d
-
Set集合:set集合不允许添加重复的元素
-
SortedSet接口:会将集合中的元素按升序进行排列,SortedSet不允许添加null元素
自动排序测试public static void main(String[] args) { SortedSet set = new TreeSet(); set.add(100); set.add(98); set.add(265); System.out.println(set); }//output:98,100,265
headSet(int x) 返回小于指定值的元素集合
tailSet(int x) 返回大于等于指定值的元素集合
-
ArrayList 类:实现动态增长容量,随机存储性能较好
ArrayList有三种构造方法:ArrayList(), ArrayList(Collection c), ArrayList(int initCapacity)
ArrayList的其他方法:
- ensureCapacity 可以指定ArrayList的大小,因为每次添加元素动态扩展后,是十分花时间的
-
LinkedList 类:继承了AbstractSequentialList,在头尾添加、删除、修改、查询元素性能较快,会自动地伸长和压缩
有两种构造函数 LinkedList(Collection c) LinkedList()
常用的函数:addFirst addLast getFirst getLast removeFirst removeLast -
HashSet 类扩展AbstractSet接口并实现Set接口,其基于散列码进行存储,速度较快,但元素排序是无序的, 如果你需要有序的Set,请使用TreeSet
//无序的验证
public class Main {
public static void main(String[] args) {
List<String> list = Arrays.asList(new String[]{"B", "A", "D", "E", "C", "F"});
HashSet hs = new HashSet(list);
System.out.println(hs);
}
} //output:A B C D E F
-
HashSet的四种构造方法:
- HashSet()
- HashSet(Collection c)
- HashSet(int initCapacity)
- HashSet(int initCapacity, float fillRatio) fillRatio是装载因子,范围在0-1.0之间,默认是0.75。当实际元素个数/容量 > fillRatio, HashSet自动进行扩容
-
TreeSet 类 对象按照升序排列,检索速度快,包含四种构造器
- TreeSet()
- TreeSet(Collection c)
- TreeSet(Comparator comp) 按照指定的办法进行排序
- TreeSet(SortedSet ss)
三、通过迭代器访问集合里的元素
使用iterator()可以方便地访问每一个元素,iterator()要么实现了Iterator,要么实现了ListIterator
ListIterator比Iterator丰富的地方在于,它允许向前,向后双端遍历,但只适用于实现List接口的类集
Iterator里面的方法
ListIterator里面的方法
实战演示
import java.util.*;
public class Main {
public static void main(String[] args) {
//初始化ArrayList,并添加元素
List al = new ArrayList(20);
al = Arrays.asList(new String[]{"C","A","E","B","D","F"});
//创建单向迭代器
System.out.println("a1 中原始内容是:");
Iterator itr = al.iterator();
while (itr.hasNext()){
Object element = itr.next();
System.out.print(String.valueOf(element)+" ");
}
System.out.println();
//创建双向迭代器,修改元素
ListIterator litr = al.listIterator();
while (litr.hasNext()){
Object element = litr.next();
litr.set(String.valueOf(element)+"+");
}
System.out.println("a1 被修改之后的内容");
//重定向
itr = al.iterator();
while (itr.hasNext()){
Object element = itr.next();
System.out.print(String.valueOf(element)+" ");
}
System.out.println();
System.out.println("反向输出");
while (litr.hasPrevious()){
Object element = litr.previous();
System.out.print(String.valueOf(element)+" ");
}
System.out.println();
}
}
//output:
/*
a1 中原始内容是:
C A E B D F
a1 被修改之后的内容
C+ A+ E+ B+ D+ F+
反向输出
F+ D+ B+ E+ A+ C+
*/
注意:remove会导致iterator删除next指向的元素,再次使用iterator遍历元素会跳过该元素
public static void main(String[] args) {
//初始化ArrayList,并添加元素
ArrayList<String> al = new ArrayList<String>(20);
al.add("C");
al.add("A");
al.add("E");
ListIterator<String> iterator = al.listIterator();
while (iterator.hasNext()) {
String letter = iterator.next();
if (letter.equals("A")) {
iterator.remove();
iterator.previous();
} else
System.out.print(letter+" ");
}
//从集合中删除元素
System.out.println("\n已经从集合中删除了元素A");
for (String a : al) System.out.print(a+" ");
}
//output:
/*
C C E
从集合中删除元素
C E
*/
Map
Map是一种key-value结构,可以根据key获得value值
key不允许重复,值可以重复
测试map功能
public static void main(String[] args) {
Map<String,Integer> map = new HashMap<String,Integer>();
map.put("A",1);
map.put("B",2);
map.put("C",3);
map.put("D",4);
//相同的键会重写覆盖
map.put("A",5);
//获取键的集合
Set keySet = map.keySet();
System.out.println(keySet);
//获取值的集合
Collection values = map.values();
System.out.println(values);
//获取每一个键值对,进行打印
for (Map.Entry entry : map.entrySet()) {
System.out.print("key = "+entry.getKey()+", ");
System.out.print("value = "+entry.getValue()+"\n");
}
}
/*OUTPUT
[A, B, C, D]
[5, 2, 3, 4]
key = A, value = 5
key = B, value = 2
key = C, value = 3
key = D, value = 4
*/
Map接口常用的方法
Map接口常用的有三个实现类,分别是:AbstractMap,HashMap(散列表结构),TreeMap(树结构)
HashMap不保证加入的顺序,有四种构造器,分别是
- HashMap()
- HashMap(Collection c)
- HashMap(int initCapacity)
- HashMap(int initCapacity, float fillRatio) fillRatio是装载因子,范围在0-1.0之间,默认是0.75。当实际元素个数/容量 > fillRatio, HashMap自动进行扩容,以保证检索速度
关于WeakHashMap,它是一个弱关键字映射,就是说如果key不再被使用,会被垃圾回收器回收
Map.Entry和SortedMap
Map.Entry是Map的一个内部类,表达一个 key/value映射关系
SortedMap关键字key按升序排序
SortedMap常用的方法
TreeMap是实现了SortedMap的完全实现类,其关键字按照升序排序
TreeMap的四种构造方法
第二个是传入一个排序策略
public static void main(String[] args) {
Map<String,Integer> map = new TreeMap<String,Integer>();
map.put("D",4);
map.put("C",3);
map.put("B",2);
map.put("A",1);
//获取键的集合
Set keySet = map.keySet();
//按照升序排列
System.out.println(keySet);
}
/*OUTPUT: [A, B, C, D]
Comparator接口
前面说过,TreeMap和TreeSet都可以基于Comparator提供的策略对插入的元素进行排序
comparator接口有两个方法,其中核心的方法是比较两个元素的关系
演示:定义一个基于字符串长度进行排序的策略
public class ComparatorBasedOnStringLength implements Comparator<String> {
@Override
public int compare(String o1, String o2) {
return o1.length() - o2.length();
}
}
public static void main(String[] args) {
TreeSet<String> set1 = new TreeSet<String>();
set1.add("AUUUU");
set1.add("BBFFFFFFFFFF");
set1.add("CCC");
System.out.println("基于默认排序策略:字典序");
System.out.println(set1);
set1 = new TreeSet<String>(new ComparatorBasedOnStringLength());
set1.add("AUUUU");
set1.add("BBFFFFFFFFFF");
set1.add("CCC");
System.out.println("基于自定义排序策略:字符串长度由短到长");
System.out.println(set1);
}
/*
output:
基于默认排序策略:字典序
[AUUUU, BBFFFFFFFFFF, CCC]
基于自定义排序策略:字符串长度由短到长
[CCC, AUUUU, BBFFFFFFFFFF]
*/
其他集合类介绍
这部分类是以前JDK版本遗留下来的,现在也被归并到类集框架
Enumeration接口
该类的功能与Iterator相似,很少被使用,有两个方法
hasMoreElements | 是否有更多的元素,返回是或否 |
---|---|
nextElement | 返回下一个元素 |
Vector类
Vector与ArrayList类似,都是动态数组,Vector实现了AbstractList接口和List接口;
区别在于Vector是同步的,而且有以前版本遗留的方法,我们既可以使用List接口的方法,也可以使用以前的方法;
Vector的构造方法
- public Vector(int initialCapacity, int capacityIncrement)
- public Vector() 初始容量大小为10
- public Vector(int initialCapacity) 这里的capacityIncrement = 0,没有指定自增扩容默认扩原来的一倍
- public Vector(Collection<? extends E> c)
Stack类
Stack是Vector的子类,其元素顺序是后进先出,Stack拥有Vector的所有方法,此外,他还有一些自己的方法。
Dictionary类
该类用法与Map类似,也是键值对类型,比较过时
HashTable类
HashTable是同步的,用法与HashMap类似,也是存储键值对类型的数据,我们既可以用Map方法对HashTable进行调用,也可以使用其原本的方法
HashTable有四种构造方法
默认装载因子0.75,当把一个Map转为HashTable时,HashTable的容量是原来Map里面元素的两倍,装载因子还是0.75
HashTable有一个方法叫做rehash,它会增大散列表大小,对关键字再散列
Properties类
是HashTable的一个子类,关键字和值都是字符串类型,是线程安全的
Properties类内部还有一个Properties的属性(这看起来很奇怪,但应该是为了适应XML而做的嵌套吧),在对properties进行检索时,如果没有找到,就会去这个对象里面去找,另外Properties支持加载和写入文件
一些Properties自带的方法
JDK文档说明:Properties虽然可以使用HashTable里面的方法,但还是建议使用SetProperty和GetProperty,否则在调用某些方法上将失败
Properties里面的load和store方法
load允许我们从读入流读取Properties文件转化为Properties对象,store方法允许我们把Properties对象持久化
代码示例
public class TestPropertiesLoadAndStore {
public static void main(String[] args) {
Properties settings = new Properties();
try{
settings.load(new FileInputStream("d:\\count.txt"));
}catch (IOException e){
settings.setProperty("count",new Integer(0).toString());
}
int c = Integer.parseInt(settings.getProperty("count"))+1;
System.out.println("本程序已经被使用"+c+"次");
settings.setProperty("count",new Integer(c).toString());
try{
settings.store(new FileOutputStream("d:\\count.txt"),"PropertiesFile use it");
}catch (IOException e){
System.out.println(e.getMessage());
}
}
}