这篇文章主要是介绍java容器的分类和一些用法。


为什么要引入Java容器?
我们知道,如果定义一个int数组,需要一开始就要制定它的大小。在一些情况下,我们根本不知道它的长度是多少,开辟很大的长度会导致空间浪费。
此外,数组还有很多缺点,例如数组中提供的方法非常有限,对于添加、删除、插入数据等操作,非常不便,同时效率不高。获取数据中实际元素的个数的需求,数组没有现成的属性或方法可用。数组存储数据的特点:有序、可重复。对于无序、不可重复的需求,不能满足。
为了数组能够更灵活的应用,提出了Java容器的概念。

JAVA容器详解
Java的容器主要分为2个大类,即Collection和Map。Collection代表着集合,类似数组,只保存一个数字。而Map则是映射,保留键值对两个值。
根据图,首先提一下List Queue Set Map 这四个的区别。

  • List(对付顺序的好帮手): 存储的元素是有序的、可重复的。
  • Set (注重独一无二的性质):存储的元素是无序的、不可重复的。
  • Queue (实现排队功能的叫号机):按特定的排队规则来确定先后顺序,存储的元素是有序的、可重复的。
  • Map (用 key 来搜索的专家) :使用键值对(key-value)存储,类似于数学上的函数 y=f(x),“x” 代表 key,“y” 代表 value,key 是无序的、不可重复的,value 是无序的、可重复的,每个键最多映射到一个值。

接下来我们就来深入探究一下吧。

1.Collection

(1).List

名称 底层 线程安全性 优点 扩容机制
ArrayList 数组 线程不安全 查找快,增删慢 首次创建长度为10,扩为1.5倍
Vector 数组 线程同步线程安全 查找快,增删慢 首次创建长度为10,*2
LinkedList 双向链表(JDK1.6 之前为循环链表,JDK1.7 取消了循环) 线程不安全 增删快,查找慢 不主动扩容

(2).Set

名称 底层 线程安全性 备注
HashSet HashMap(数组+链表) 线程不安全 注意hashcode和equals()
LinkedHashSet 链表和哈希表 线程不安全 HashSet的子类,元素的插入和取出顺序满足 FIFO
TreeSet 红黑树 线程不安全 支持对元素自定义排序规则

TreeSet中的自然排序和定制排序
(1)自然排序:在所属的类中加上排序

实现类

package TreeSet;  //1.自然排序 public class Person implements Comparable{     private int age;     private String name;     private int score;      public Person(int age,String name,int score){         this.age=age;         this.name=name;         this.score=score;     }          @Override     public int compareTo(Object o) {         //强制转换对象         //按年龄和分数排序 都是从大到小         if(o instanceof Person){             Person O=(Person) o;//强转类型             if(this.age!=O.age)             return this.age-O.age;//this是当前的主体,此时返回的应该是升序             else return O.score-this.score;         }else throw new RuntimeException("不属于此类型");     }      @Override     public String toString() {         return "Person{" +                 "age=" + age +                 ", name='" + name + '\'' +                 ", score=" + score +                 '}';     } } 

测试类

package TreeSet;  import java.util.Arrays;  public class Test {     public static void main(String[] args) {         Person[] person=new Person[3];         person[0]=new Person(5,"guolu",99);         person[1]=new Person(3,"cherry",98);         person[2]=new Person(5,"cherry",98);         Arrays.sort(person);//别忘了这句话;         for(int i=0;i<3;i++){             System.out.println(person[i].toString());         }     } }  

(2)定制排序:向其中传入已经重写Comparator中方法的对象。

public class Test {     public static void main(String[] args) {         Person[] person=new Person[3];         person[0]=new Person(5,"guolu",99);         person[1]=new Person(3,"cherry",98);         person[2]=new Person(2,"cherry",98);          Comparator com=new Comparator() {             @Override             public int compare(Object o1, Object o2) {                 Person p1=(Person)o1;                 Person p2=(Person)o2;                 return p1.getAge()-p2.getAge();//得确保有get和set接口,这边好像不太好用compareTo,暂时不知道为啥             }         };         Arrays.sort(person,com);         for(int i=0;i<3;i++){             System.out.println(person[i].toString());         }     } } 

(3).Queue

queue:单向队列
deque:双向队列
PriorityQueue 是非线程安全的,默认小顶堆,但可以接收一个 Comparator 作为构造参数,从而来自定义元素优先级的先后。

2.Map

名称 底层 线程安全性 备注 扩容机制
HashMap 数组+链表(jdk7) 数组+链表+红黑树 (jdk8) 线程不安全 能存储null的key和value 首次创建长度16,扩容2倍,jdk8中当数组的某一个索引位置上的元素以链表形式存在的数据个数>8且当前的数组长度>64时,此索引位置上的所有数据改为使用红黑树存储
LinkedHashMap 同hashmap 线程不安全 比hashmap多了指向前驱和后继的两个指针
ConcurrentHashMap 同hashmap 线程安全 使用16个锁来控制segments,分段锁
HashTable 数组+链表 线程安全,全表锁 不能存储null的key和value 首次创建时长度为11,后来变为2n+1
TreeMap 红黑树 线程不安全 定制排序

1.集合转换为数组

Collection coll=new ArrayList(); Object arr[]=coll.toArray(); for(int i=0;i<arr.length;i++){ System.out.println(arr[i]); } 

2.数组转换为集合
asList后面的必须接引用类型

List<String> list=Arrays.asList(new String[]{"AA","BB","CC"}); System.out.println(list); 

3.红黑树
参考:红黑树

javaguide、尚硅谷