JAVA基础之集合框架详解
参考文章:
https://www.cnblogs.com/xiaoxi/p/6089984.html
http://www.importnew.com/16658.html
1.集合框架图
Java的集合类主要由两个接口派生而出:Collection和Map,Collection和Map是Java集合框架的根接口,这两个接口又包含了一些子接口或实现类。
image.png2.Collection接口(Collection包含了List和Set两大分支。)
2.1 List接口的实现类(ArrayList,Vector,LinkedList,Stack)
(1).ArrayList
ArrayList是一个动态数组,它允许任何符合规则的元素插入甚至包括null,每一个ArrayList都有一个初始容量(10),随着容器中的元素不断增加,容器的大小也会随着增加。在每次向容器中增加元素的同时都会进行容量检查,当快溢出时,就会进行扩容操作。所以如果我们明确所插入元素的多少,最好指定一个初始容量值,避免过多的进行扩容操作而浪费时间、效率。
注意: ArrayList擅长于随机访问。同时ArrayList是非同步的。
(2).Vector
与ArrayList相似,但是Vector是同步的。所以说Vector是线程安全的动态数组。它的操作与ArrayList几乎一样。
(3).LinkedList
同样实现List接口的LinkedList与ArrayList不同,ArrayList是一个动态数组,而LinkedList是一个双向链表,
由于实现的方式不同,LinkedList不能随机访问,它所有的操作都是要按照双重链表的需要执行。在列表中索引的操作将从开头或结尾遍历列表(从靠近指定索引的一端)。这样做的好处就是可以通过较低的代价在List中进行插入和删除操作。
与ArrayList一样,LinkedList也是非同步的。如果多个线程同时访问一个List,则必须自己实现访问同步。
注意:创建List时构造一个同步的List:List list = Collections.synchronizedList(new LinkedList(...));
(4).Stack
Stack继承自Vector,实现一个后进先出的堆栈。Stack提供5个额外的方法使得Vector得以被当作堆栈使用。基本的push和pop 方法,还有peek方法得到栈顶的元素,empty方法测试堆栈是否为空,search方法检测一个元素在堆栈中的位置。Stack刚创建后是空栈。
private static void testStack() {
/***
* 栈是一种只能在一端进行插入或删除操作的线性表
* 特性:先进后出
*/
Stack<String> stack=new Stack<>();
//进栈push()
stack.push("1");
stack.push("2");
stack.push("3");
stack.push("4");
System.out.println("statck data:"+stack.toString());
// 取栈顶值(不出栈)
System.out.println("stack top:"+stack.peek());
//出栈
// stack.pop();
// stack.pop();
//stack.pop();
System.out.println("stack data:"+stack.toString());
System.out.println("stack is empty:"+stack.empty());
int index=stack.search("3");//计数从顶部开始
System.out.println("stack search index:"+index);
System.out.println("stack search result:"+ stack.get(0));
List<String> list=new ArrayList<>();
list.add("1");
list.add("2");
list.add("3");
list.add("4");
System.out.println("list is empty:"+list.get(3));
Iterator<String> iterator=list.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}
}
2.2 Set接口的实现类(HashSet,LinkedHashSet,TreeSet)
(1)HashSet
HashSet 是一个没有重复元素的集合。它是由HashMap实现的,不保证元素的顺序(这里所说的没有顺序是指:元素插入的顺序与输出的顺序不一致),而且HashSet允许使用null 元素。HashSet是非同步的,如果多个线程同时访问一个哈希set,而其中至少一个线程修改了该set,那么它必须保持外部同步。 HashSet按Hash算法来存储集合的元素,因此具有很好的存取和查找性能。
注意:HashSet是由HashMap实现,不保证元素的插入顺序,可以存放null值,仅仅能够存入一个null值。
private static void testHashSet() {
/****
* 元素不重复
*/
Set<String> hashSet=new HashSet<>();
hashSet.add("javabbb");
hashSet.add("java01");
hashSet.add("java01");
hashSet.add("java03");
hashSet.add("java02");
Set<String> hashSet1=new HashSet<>();
hashSet1.add("java05");
hashSet1.add("java04");
hashSet1.add("javaaaa");
hashSet.add(null);//可以插入null
hashSet.add(null);
hashSet.addAll(hashSet1);
boolean isEmpty=hashSet.isEmpty();
//遍历
Iterator<String> iterator= hashSet.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}
}
输出结果:
image.png
(2)LinkedHashSet
LinkedHashSet继承自HashSet,其底层是基于LinkedHashMap来实现的,有序,非同步。LinkedHashSet集合同样是根据元素的hashCode值来决定元素的存储位置,但是它同时使用链表维护元素的次序。这样使得元素看起来像是以插入顺序保存的,也就是说,当遍历该集合时候,LinkedHashSet将会以元素的添加顺序访问集合的元素。
注意:LinkedHashSet底层是基于LinkedHashMap来实现
private static void testLinkedHashSet() {
/****
* 因为是链表,所以有序输出
* 元素不重复
*/
Set<String> linkedHashSet=new LinkedHashSet<>();
linkedHashSet.add("java01");
linkedHashSet.add("java01");
linkedHashSet.add("java02");
linkedHashSet.add("java03");
Set<String> linkedHashSet1=new LinkedHashSet<>();
linkedHashSet1.add("java04");
linkedHashSet1.add("java05");
linkedHashSet1.add(null);
linkedHashSet1.add(null);
linkedHashSet.addAll(linkedHashSet1);
//遍历
Iterator<String> iterator= linkedHashSet.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}
}
输出结果:
image.png
(3)TreeSet
TreeSet是一个有序集合,其底层是基于TreeMap实现的,非线程安全。TreeSet可以确保集合元素处于排序状态。TreeSet支持两种排序方式,自然排序和定制排序,其中自然排序为默认的排序方式。当我们构造TreeSet时,若使用不带参数的构造函数,则TreeSet的使用自然比较器;若用户需要使用自定义的比较器,则需要使用带比较器的参数。
注意:TreeSet底层是基于TreeMap来实现,Set集合都是非线程安全的
private static void testIntegerSort() {
System.out.println("Integer对象自然排序:");
TreeSet<Integer> treeSetFirst = new TreeSet<>();
treeSetFirst.add(2);
treeSetFirst.add(1);
treeSetFirst.add(4);
treeSetFirst.add(3);
treeSetFirst.add(5);
Iterator<Integer> iterator=treeSetFirst.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}
}
private static void testDictionarySort() {
System.out.println("Dictionary对象自然排序:");
TreeSet<String> treeSetFirst = new TreeSet<>();
treeSetFirst.add("Baidu");
treeSetFirst.add("Tecent");
treeSetFirst.add("Ali");
treeSetFirst.add("WanDa");
treeSetFirst.add("HengDa");
treeSetFirst.add("12");
treeSetFirst.add("23a#");
treeSetFirst.add("#");
Iterator<String> iterator=treeSetFirst.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}
}
private static void testCompatorSort() {
Set<Student> treeSet=new TreeSet<>();
treeSet.add(new Student("tecent",2));
treeSet.add(new Student("JD",1));
treeSet.add(new Student("wanda",3));
treeSet.add(new Student("baidu",2));
treeSet.add(new Student("ali",2));
treeSet.add(new Student("tecent",2));//重复的元素被剔除了
System.out.println(treeSet);
Iterator itTSet = treeSet.iterator();//遍历输出
while(itTSet.hasNext()){
System.out.print(itTSet.next() + "\n");
}
}
private static void testSubHeadTailSet() {
TreeSet nums = new TreeSet();
nums.add(5);
nums.add(2);
nums.add(3);
nums.add(8);
nums.add(8);
//输出集合元素,可以看到集合元素已经处于排序状态,输出【2,3,5,8】
System.out.println(nums);
//输出排序后集合里的第一个元素2
System.out.println(nums.first());
//输出排序后集合里最后一个元素
System.out.println(nums.last());
//输出小于4的集合,不包含4,输出【2,3】
System.out.println(nums.headSet(4));
//输出大于5的集合,如果set集合中有5,子集中还应该有5,输出【5,8】
System.out.println(nums.tailSet(5));
//输出大于2,小于5的子集,包括2,不包括5,输出集合【2,3】
System.out.println(nums.subSet(2, 5));
}
public static class Student implements Comparable {
int num;
String name;
public Student( String name,int num) {
this.num = num;
this.name = name;
}
@Override
public String toString() {
return "StudentNo:" + num + " ,StudentName:" + name ;
}
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public int compareTo(Object o) {
Student student= (Student) o;
if(num<student.getNum()){//升序排列
return -1;
}else if(num==student.getNum()){
return name.compareTo(student.getName());
}else{
return 1;
}
}
}
输出结果:
image.png
3.Map接口
Map与List、Set接口不同,它是由一系列键值对组成的集合,提供了key到Value的映射。同时它也没有继承Collection。在Map中它保证了key与value之间的一一对应关系。也就是说一个key对应一个value,所以它不能存在相同的key值,当然value值可以相同。
(1).HashMap
HashMap可以通过调用Collections的静态方法Collections.synchronizedMap(Map map)进行同步,最多只允许一条记录的键为Null,不支持线程的同步,无序
private static void testHashMap() {
/***
* hashmap的key和value都可以为null
*/
Map<String, String> map = new HashMap<>();
for (int i = 0; i <= 3; i++) {
map.put("key" + i, "value" + i);
}
map.put(null,"value4");
map.put(null,"value5");
map.put("key6",null);
map.put("key7",null);
map.get("key" + 5);
for (String key : map.keySet()) {
System.out.println(map.get(key));
}
}
输出结果:
image.png
输出结果:
image.png
(2).LinkedHashMap
LinkedHashMap是HashMap的一个子类,它保留插入的顺序,如果需要输出的顺序和输入时的相同,那么就选用LinkedHashMap。允许使用null值和null键
private static void testLinkHashMap() {
//linkedhashmap extends hashmap 比hashmap功能更强大
Map<String, String> map = new LinkedHashMap<>();
for (int i = 0; i <= 3; i++) {
map.put("key" + i, "value" + i);
}
map.put(null,"value4");
map.put(null,"value5");
map.put("key6",null);
map.put("key7",null);
map.get("key" + 5);
for (String key : map.keySet()) {
System.out.println(map.get(key));
}
}
输出结果:
image.png
(2).Hashtable
线程同步,同时key,value都不可以为null,无序的
private static void testHashtable() {
/***
* 线程同步的,同时key,value都不可以为null,无序的
*/
Hashtable<String,Object> hashtable = new Hashtable();
hashtable.put("baidu","101");
hashtable.put("ali","102");
hashtable.put("tencent","103");
hashtable.put("wanda","105");
hashtable.put("pingan","107");
hashtable.put("hengda","106");
hashtable.put("transsion","104");
// hashtable.put(null,"2");//java.lang.NullPointerException
// hashtable.put("wanke",null);//java.lang.NullPointerException
for(String key:hashtable.keySet()){
System.out.println(key+"="+hashtable.get(key));
}
}
(4).ConCurrentHashMap
ConcurrentHashMap和HashTable都是线程安全的,无序的,key和value都不能为null,性能上要比Hashtable要强,是一个加强版本的Hashtable。
private static void testConcurrentHashMap() {
/***
* ConcurrentHashMap和HashTable都是线程安全的,可以在多线程中进行,
* key和value都不能为null,性能上要比Hashtable要强
* 线程同步的,同时key,value都不可以为null
*/
ConcurrentHashMap<String,Object> concurrentHashMap = new ConcurrentHashMap();
concurrentHashMap.put("baidu","101");
concurrentHashMap.put("ali","102");
concurrentHashMap.put("tencent","103");
concurrentHashMap.put("wanda","105");
concurrentHashMap.put("pingan","107");
concurrentHashMap.put("hengda","106");
concurrentHashMap.put("transsion","104");
// concurrentHashMap.put(null,"2");//java.lang.NullPointerException
// concurrentHashMap.put("wanke",null);//java.lang.NullPointerException
for(String key:concurrentHashMap.keySet()){
System.out.println(key+"="+concurrentHashMap.get(key));
}
}
输出结果:
image.png
(5).TreeMap
TreeMap 是一个有序的key-value集合,非同步,基于红黑树(Red-Black tree)实现,每一个key-value节点作为红黑树的一个节点。TreeMap存储时会进行排序的,会根据key来对key-value键值对进行排序,其中排序方式也是分为两种,一种是自然排序,一种是定制排序,具体取决于使用的构造方法。
注意:key不能为null,value可以为null
//自然排序顺序:
public static void naturalSort(){
//第一种情况:Integer对象
System.out.println("Integer对象自然排序:");
TreeMap<Integer,String> treeMapFirst = new TreeMap<Integer, String>();
treeMapFirst.put(1,"jiaboyan");
treeMapFirst.put(6,"jiaboyan");
treeMapFirst.put(3,"jiaboyan");
treeMapFirst.put(10,"jiaboyan");
treeMapFirst.put(7,"jiaboyan");
treeMapFirst.put(13,"jiaboyan");
//treeMapFirst.put(null,"jiaboyan");java.lang.NullPointerException
treeMapFirst.put(14,null);//可以运行
System.out.println(treeMapFirst.toString());
//第二种情况:SortedTest对象
System.out.println("SortedTest对象排序一:");
TreeMap<SortedTest,String> treeMapSecond = new TreeMap<SortedTest, String>();
treeMapSecond.put(new SortedTest(10),"jiaboyan");
treeMapSecond.put(new SortedTest(1),"jiaboyan");
treeMapSecond.put(new SortedTest(13),"jiaboyan");
treeMapSecond.put(new SortedTest(4),"jiaboyan");
treeMapSecond.put(new SortedTest(0),"jiaboyan");
treeMapSecond.put(new SortedTest(9),"jiaboyan");
System.out.println(treeMapSecond.toString());
//默认是根据key的自然排序来组织(比如integer的大小,String的字典排序)
System.out.println("integer和字典对象排序二:");
TreeMap<String,SortedTest> treeMapThree = new TreeMap<String,SortedTest >();
treeMapThree.put("2key1",new SortedTest(10));
treeMapThree.put("1key2",new SortedTest(1));
treeMapThree.put("bey3",new SortedTest(13));
treeMapThree.put("key6",new SortedTest(4));
treeMapThree.put("key5",new SortedTest(0));
treeMapThree.put("key4",new SortedTest(9));
System.out.println(treeMapThree.toString());
}
public static class SortedTest implements Comparable<SortedTest> {
private int age;
public SortedTest(int age){
this.age = age;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "age:"+age;
}
//自定义对象,实现compareTo(T o)方法:
public int compareTo(SortedTest sortedTest) {
int num = this.age - sortedTest.getAge();
//为0时候,两者相同:
if(num==0){
return 0;
//大于0时,传入的参数小:
}else if(num>0){
return 1;
//小于0时,传入的参数大:
}else{
return -1;
}
}
}
输出结果:
image.png