一、概述
1.定义
1:集合本身就是一个容器,一个java对象,集合储存的是对象的内存地址。
2:在java中每一个不同的集合,底层会对应不同的数据结构。(往集合c1中放数
据,可能放到数组上了,往集合c2中放数据,可能放到二叉树上了。)
3:所有的集合类和集合接口都在java.util包下。
4:在java中集合分为两大类:
一类是单个方式储存元素:
单个方式储存元素,这一类集合中超级父接口:java.util.Collection;
一类是以键值对的方式储存元素:
以键值对的方式储存元素,这一类集合中超级父接口:java.util.map;
5:collection中能存放什么元素?
没有使用”泛型”之前,collection中可以存储Object的所有子类型。
使用了”泛型”之后,collection中只能存储某个具体的类型
Collection
1. Set(无序不可重复)
- TreeSet:基于红黑树实现,支持有序性操作,例如根据一个范围查找元素的操作。但是查找效率不如 HashSet,HashSet 查找的时间复杂度为 O(1),TreeSet 则为 O(logN)。
解释:SortedSet集合存储元素的特点:由于继承了Set集合,所以它的特点也是无序不可重复,但是放在SortedSet集合中的元素可以自动排序我们成为可排序集合。放到该集合中的元素是自动按照大小顺序排序的。
- HashSet:基于哈希表实现,支持快速查找,但不支持有序性操作。并且失去了元素的插入顺序信息,也就是说使用 Iterator 遍历 HashSet 得到的结果是不确定的。
LinkedHashSet:具有 HashSet 的查找效率,并且内部使用双向链表维护元素的插入顺序。
2. List(有序可重复)
ArrayList:基于动态数组实现,支持随机访问。
- Vector:和 ArrayList 类似,但它是线程安全的。
LinkedList:基于双向链表实现,只能顺序访问,但是可以快速地在链表中间插入和删除元素。不仅如此,LinkedList 还可以用作栈、队列和双向队列。
3. Queue
LinkedList:可以用它来实现双向队列。
PriorityQueue:基于堆结构实现,可以用它来实现优先队列。
Map
所有的Map的key都是无序不可重复
TreeMap:基于红黑树实现。
- HashMap:基于哈希表实现。
- HashTable:和 HashMap 类似,但它是线程安全的,这意味着同一时刻多个线程同时写入 HashTable 不会导致数据不一致。它是遗留类,不应该去使用它,而是使用 ConcurrentHashMap 来支持线程安全,ConcurrentHashMap 的效率会更高,因为 ConcurrentHashMap 引入了分段锁。
- LinkedHashMap:使用双向链表来维护元素的顺序,顺序为插入顺序或者最近最少使用(LRU)顺序。
总结-开发中如何选择
1.一组对象(Collection接口)
允许重复: List
增删多:LinkedList(底层双向链表)
改查多:ArrayList(底层数组)
不允许重复: Set
无序:HashSet(底层HashMap,既(数组+链表+红黑树)
排序:TreeSet
插入和取出顺序一致:LinkedHashSet(数组+双向链表)
2.一组键值对(Map)
键无序:HashMap
键排序:TreeMap
键插入和取出顺序一致:LinkedHashMap
读取文件:Properties
二、容器中的设计模式
迭代器模式
Collection 继承了 Iterable 接口,其中的 iterator() 方法能够产生一个 Iterator 对象,通过这个对象就可以迭代遍历 Collection 中的元素。
JDK 1.5 引入了增强的for循环,简化了迭代容器时的写法。
for (元素类型 变量名 : 数组或集合) {
System.out.println(变量名);
}
//使用增强for迭代
ArrayList<String> list = new ArrayList<String>();
list.add(new String("Monday"));
list.add(new String("Tuesday"));
list.add(new String("Wensday"));
for(String weekday : list){//enhanced for statement
System.out.println(weekday.toUpperCase());
}
迭代器iterator
在Map中不能用,在所有Collection以及子类中使用
Collection c = new Arraylist();
c.add("abc");
c.add(123);
c.add(new Object());
//第一步:获取集合迭代器对象Iterator
Iterator it = c.itrator();
/*第二部:通过以上获取的迭代器对象开始迭代
以下两个方法是迭代器对象Iterator中的方法:
boolean hasNext() 如果仍有对象可以迭代则返回 true
Object next() 返回迭代的下一个元素
*/
while(it.hasNext()){
Object obj = it.next();
System.out.println(obj);
}
}
}
适配器模式
Arrays.asList()
该方法是将数组转化成List集合的方法。
List<String> list = Arrays.asList("a","b","c");
(1)该方法不建议使用于基本数据类型的数组(byte,short,int,long,float,double,boolean),
该方法适用于对象型数据的数组(String、Integer…)
(2)不支持add()、remove()、clear()等方法
为什么不支持add()、remove()、clear()等方法???
这样是不行的
String [] arr= new String[]{"张三","李四"};
List<String> list = Arrays.asList(arr);
//也可以这样写
//List<String> list = Arrays.asList("张三","李四");
list.add("王五");
异常如下:
java.lang.UnsupportedOperationException
at java.util.AbstractList.add(AbstractList.java:148)
at java.util.AbstractList.add(AbstractList.java:108)
at com.example.demo.ClassTest.test2(ClassTest.java:49)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
为什么会这样呢,看下源码就很清楚了:
public static <T> List<T> asList(T... a) {
return new ArrayList<>(a);
}
/**
* @serial include
*/
private static class ArrayList<E> extends AbstractList<E>
implements RandomAccess, java.io.Serializable
{
private static final long serialVersionUID = -2764017481108945198L;
private final E[] a;
ArrayList(E[] array) {
a = Objects.requireNonNull(array);
}
Arrays.asList 方法会创建一个 ArrayList,注意 这个 ArrayList 是 Arrays 的内部类 ,不是 java.util 下的ArrayList.它继承了AbstractList 但是没有重写 AbstractList 的 add 方法.
而 AbstractList 的 add 方法是默认直接抛出 UnsupportedOperationException 的。
public boolean add(E e) {
add(size(), e);
return true;
}
public void add(int index, E element) {
throw new UnsupportedOperationException();
}
解决办法
String [] arr= new String[]{"张三","李四"};
List<String> myList= new ArrayList<String>(Arrays.asList(arr));
myList.add("王五");
三、常用的方法
1.Collection
public class CollectionTest01 {
public static void main(String[] args) {
Collection c =new ArrayList();
//向集合中添加元素
c.add(1200);//自动装箱(java5的新特性。),实际上是放进去了一个对象的内存地址。Integer x = new Integer(1200);c.add(new Object());
//获取集合中元素的个数
System.out.println("集合中元素个数是:" + c.size();// 2
//判断集合中是否包含1200
boolean flag = c.contains (1200);
System.out.println(flag);// true
//清空是c.clear();
//删除集合中某个元素
// c.remove(1);
//判断集合是否为空
// system.out.println(c.isEmpty()); // false
//转换成数组(了解,使用不多。)
//object[] objs = c.toArray ();
}
}
2.List
public class ListMethod {
@SuppressWarnings("all")
public static void main(String[] args)(
//void add(int index, Object ele)在index位置插入ele元素
//boolean addAll(int index,Collection eles)从index位置开始将eles中所有的元素添加进来。
//Object get(int index)获取指定index位置的元素
//int indexOf(Object obj) 返回obj在集合中首次出现的位置 lastIndex时末次
//Object remove(int index)移除指定index位置的元素,并返回此元素
//Object set(int index,0bjext ele)设置指定index位置的元素为ele,相当于是替换
//List subList(int fromIndex,int toIndex) 返回从fromIndex到 toIndex位置的子集合。
}
}
3.contains,remove方法分析
深入理解contains方法
contains方法调用了equals方法进行比对。
因为String类重写了equals方法,如果是 User s1 = new User(“abc”),则结果是false。(必须重写equals方法)
import java.util.ArrayList;
import java.util.Collection;
/*
contains方法是用来判断集合中是否包含某个元素的方法。
那么他在底层中是怎么判断集合中是否包含某个元素的呢?
调用了equals方法进行比对。
*/
public class collectionTest02 {
public static void main(String[] args) {
//创建集合对象
Collection c = new ArrayList();
//向集合中存储元素
String s1 =new String("abc " );
c.add(s1);
String s2 = new String("def ");
c.add(s2);
String x= new String("abc ");
System.out.println(c.contains(x));//true
}
}
深入理解remove方法
调用了equals方法
import java.util.ArrayList;
import java.util.Collection;
/*
contains方法是用来判断集合中是否包含某个元素的方法。
那么他在底层中是怎么判断集合中是否包含某个元素的呢?
调用了equals方法进行比对。
*/
public class collectionTest02 {
public static void main(String[] args) {
//创建集合对象
Collection c = new ArrayList();
//创建字符串对象
String s1 = new String("hello");
//加进去
c.add(s1);
//创建一个新的字符串对象
String s2 = new String("hello");
//删除s2
c.remove(s2);
//集合元素的个数是?
System.out.println(c.size());//0
}
}