一 Collection
1.1概念
集合存储的优点: 初始化时长度可不定 提供的方法比较多 对于增删改 效率较高 可有序 可无序 可重复 可不重复
1.2 体系结构
/**
* 分为Collection 和Map体系
*Collection接口: 单列数据 常用的实现类 List 有序,可重复 Set 无序,不可重复
* ArrayList LinkedList Vector
* HashSet,Linked,TreeSet
* Map: 双列数据 key-value数据存储
* HashMap LinkedMap TreeMap HashTable Properties
*/
1.3 Collection中的方法
@Test
public void te1() {
Collection coll = new ArrayList();
Collection coll1 = new ArrayList();
//boolean add(E e);//添加元素
coll.add(new Date());
System.out.println(coll.size());//1 有多少元素
coll1.add(120);
//addAll(Collection coll)
coll.addAll(coll1);
System.out.println(coll.size());//2
System.out.println(coll);//相当于toString ArrayList的
//boolean isEmpty(); 判断里面是否有数据
System.out.println(coll.isEmpty());//false
//void clear(); 清空元素 仍保留对象
coll.clear();
System.out.println(coll.isEmpty());//true
// boolean contains(Object o); 判断的不是地址值而是内容
// 在判断是 会调用对象自己重写的equals 内容相等
coll.add(110);
System.out.println(coll.contains(110));//true
Collection coll3 = Arrays.asList(110);
// boolean containsAll(Collection<?> c); 判断coll3是否全部都在coll里面
System.out.println(coll.containsAll(coll3));//true
// boolean remove(Object o); 也是从第一个开始找 既然是找内容相等 就依然要调用equals
System.out.println(coll.remove(110));
coll.add(110);
// boolean removeAll(Collection<?> c); 依然要调用equals
System.out.println(coll.removeAll(coll3));//true
}
@Test
public void te2() {
Collection coll = new ArrayList();
Collection coll1 = new ArrayList();
//boolean add(E e);//添加元素
coll.add(123);
coll.add(456);
coll1.add(123);
// boolean retainAll(Collection<?> c);保留一样的,删除不一样的
System.out.println(coll.retainAll(coll1));//true
System.out.println(coll);
// boolean equals(Object o);
System.out.println(coll.equals(coll1));//true ArrayList 是有序的 所以顺序不对也是false
// int hashCode(); 返回当前对象的hash值
System.out.println(coll.hashCode());
// 集合->Array数组Object[] toArray();
Object[] b = coll.toArray();
// 数组->集合 public static <T> List<T> asList(T... a)
List<int[]> ints = Arrays.asList(new int[]{123});
System.out.println(ints);//[[I@4ee285c6] 一维数组 只有一个对象 认为是一个元素
List arr = Arrays.asList(123, 456);
System.out.println(arr);//[123, 456]
}
2. Iterator 迭代器(遍历集合)
其对象主要用于遍历Collection集合中的元素, 主要就是为容器 遍历对象。
// hasNext(); 判读是否还有下一个元素
// next();指针下移并返回
// void remove() 删除集合中的元素 删除 的是指针所指的元素
@Test
public void te3() {
Collection coll = Arrays.asList(123, 456, false, "123");
//Iterator<E> iterator();每次调用coll.iterator(); 都会返回一个新的Iterator对象
Iterator iterator = coll.iterator();
//iterator的遍历
// boolean hasNext(); 判读是否还有下一个元素
while (iterator.hasNext()) {
// E next(); 1.初始的时候指向的是第一个元素上面 2.指针下移 3.下移之后 把下移之后的元素返回
System.out.println(iterator.next());
// foreach 内部调用的仍然是迭代器
// 执行过程 就是 每次取出coll中的一个元素 赋值给Object obj
for (Object obj : coll) {
System.out.println(obj);
}
}
}
3.ArrayList
3.1 概念
作为list的主要实现类 线程不安全的,效率高 底层使用 Object[]
3.2 jdk7和jdk8的源码区别
//1.7源码 创建初始化为10的一个数组 然后不够以1.5倍容量进行扩充,并Arrays.copyOf()把之前的复制 相当于饿汉式
//1.8 初始化时没有创建 而是add操作时进行创建 长度为10 的数组 其后相等 相当于懒汉式
4.LinkedList
4.1概念
对于频繁的 插入,删除操作 主要存着的就是对上一个元素和下一个元素的标识 可以把它转移给新的元素,只影响相邻的2个元素。
底层双向链表 既知道上面的,也知道下面的。
4.2底层实现
transient Node<E> first; transient Node<E> last; 默认值为null add(123)
//把123封装到Node中 其内部的Node 体现了双向链表
private static class Node<E> {
E item;
Node<E> next;
Node<E> prev;
Node(Node<E> prev, E element, Node<E> next) {
this.item = element;
this.next = next;
this.prev = prev;
}
}
5. Vector
5.1概念
作为list的古老实现类 线程安全的,效率低
5.2 底层使用
protected Object[] elementData;
//初始化为10 的数组扩容为原理数组的2倍 线程安全一般也不用
6.List的常用方法
@Test
public void teList() {
//List 主要就是比 Collection 多了几个索引的方法
ArrayList aList = new ArrayList();
aList.add(123);
aList.add(456);
aList.add(123);
aList.add("hhh");
// public void add(int index, E element)
aList.add(2, 234);//在index 位置,插入element
System.out.println(aList);//[123, 456, 234, 123, hhh]
List l = Arrays.asList("aa", "bb");
// public boolean addAll(int index, Collection<? extends E> c) 在index位置上 添加一个集合
// 如果是 add(l) 是把l看成一个整体 即不管l有几个元素 添加进去时都会当成一个集合元素
aList.addAll(1, l);
// public E get(int index) 获取第index个元素
System.out.println(aList.get(1));//aa
// public int indexOf(Object o) 返回集合中首次出现的位置 不存在返回-1
System.out.println(aList.indexOf(123));
// public int lastIndexOf(Object o) 返回集合中最后一次出现的位置 不存在返回-1
// public E remove(int index) 删除index位置的元素 返回删除的元素 删除之后后面往前移动
// 注意Collection 中也有个 boolean remove(Object o) 删除的是那个元素
System.out.println("remove"+aList.remove(2));
// public List<E> subList(int fromIndex, int toIndex) 返回的是左闭右开的集合
System.out.println("subList"+aList.subList(1, 3));
}
Set
1.并没有定义新的方法,主要是其父类Collection的
2.无序性:不等于随机性。并非按照数组的索引添加,而是按照数据的hash值决定的
3.不可重读性: 按照equals 判断是否相等,即要有重写equals 在判断前会进行hashCode
7.HashSet
7.1概念
作为set的主要实现类 可以存null值
7.2.底层分析
* 添加元素的过程
* 存放一个元素时计算其hash值,经过计算得出其应该放在那个位置上(这个是数组的索引)(底层实现是数组+链表),如果有第二个元素
* 也在此位置上,判断其hash值是否相等,如果相等再判断equals方法,如果还相等,则不添加,反之hash或者equals不等,
* 则加在其索引位置的链表上,以链表的方式存储,
* jdk7 该元素放在数组中指向原来的元素,
* jdk8原来的元素位置不变指向该元素
*要求:向Set中添加数据 ,其 数据所在的类 要 重写equals和hashCode方法
8.LinkedHashSet
8.1概念
作为HashSet的子类 ,遍历时是按添加的顺序遍历的,在添加数据的同时还保存了两个引用,即上一个 和下一个,记录前一个数据 和后一个数据。
8.2底层结构理解
9.TreeSet
9.1 概念
可以按照添加对象的指定属性进行排序
9.2排序要求
1.要求添加的数据必须是相同类的对象
2。自燃排序 要求添加的的数据重写 public int compareTo(Object o) 排序从小到打大(默认)还是从大到小是根据compareTo(Object o) 决定的
特殊 TreeSet默认是按照compareTo比较的 如果这个方法返回0 默认认为就是相等的 则此不会进行添加
3.定制排序
@Test
public void teTreeSet(){
//自然排序要求添加的的数据重写 public int compareTo(Object o)
//排序从小到打大(默认)还是从大到小是根据compareTo(Object o) 决定的
Set set = new TreeSet();
set.add(new User("aa",12));
set.add(new User("cc",12));
set.add(new User("bb",18));
// User{name='aa', age='12'}
//User{name='bb', age='18'}
//User{name='cc', age='12'}
for (Object o:
set) {
System.out.println(o);//h h 123
}
//定制排序 public TreeSet(Comparator<? super E> comparator) 此时按照 Comparator中的compare 进行排序
Comparator comparator = new Comparator() {
@Override
public int compare(Object o1, Object o2) {
if (o1 instanceof User && o2 instanceof User) {
User user1 = (User)o1;
User user2 = (User)o2;
return Integer.compare(user1.age, user2.age);
}else {
throw new RuntimeException("类型不匹配");
}
}
};
Set set1 = new TreeSet(comparator);
set1.add(new User("aa",12));
set1.add(new User("cc",14));
set1.add(new User("bb",18));
System.out.println("~~~~~~~~~~~~~~~~~~~");
for (Object o:
set1) {
System.out.println(o);//h h 123
}
// User{name='aa', age='12'}
//User{name='cc', age='14'}
//User{name='bb', age='18'}
}
User中定义的compareTo
@Override
public int compareTo(Object o) {
if (o instanceof User){
User user = (User)o;
//根据名字的顺序进行比较 此时调的是String的compareTo
return this.name.compareTo(user.name);
}else {
throw new RuntimeException("类型不匹配");
}
}
二 Map
1.概念
双列数据 存储key-value数据
2.结构
/*
HashMap 作为主要的实现类 线程不安全 效率高 可以存储null的key和Value
LinkedHashMap 遍历元素时,按照添加的顺序遍历的 在HashMap的基础上 增加了指针 频繁遍历是使用
TreeMap 主要用来排序 ,此时考虑key 的自然排序或者定制排序,底层是红黑树 和TreeList
Hashtable 古老实现类线程安全,效率低
Properties key和value都是String 主要用来做配置文件
*/
3.Map结构理解
Map 中的key-value 结构 key无序,使用set的去存储不重复 所以key 所在的类要重写 equals 和 hashCode方法
value可重复 用collection存储 所在的类要重写 equals
Map中的Entry : key-value构成了Entry对象 无序,不可重复,用set储存
4.HashMap
1.概念
作为主要的实现类 线程不安全 效率高 可以存储null的key和Value
2.底层实现原理
/*底层:
jdk7的时候 数组+链表 长度16的数组 Entry数组 put 时 计算hash值得到其存放位置 其位置为空时,添加成功 位置不为空时
比较key的hash值 hash值不同添加成功 相同 比较equals 再相同 把新的value替换到原来的value上 反之 添加成功
当put不下时 扩容为原来长度的两倍 扩容并非到16时才扩容 16*0.75时候(且要存放的位置非空)就扩容
8的时候 链表+数组+ 红黑树 当链表长度大于8 且当前数组的长度大于64时会用红黑树
临界值:length*0.75
加载因子:0.75 小了数组利用率低 大了链表中的数据过多
存在加载临界值的原因就是 既然是通过hash值计算的索引(具有不确定性),那就是不像数组那样 为空就去填充 ,或许一个位置通过链表存放了很多个,
但是其还有很多位置为空
new 的时候并没有赋予长度 当首次调用put时 创建长度为16的数组 底层数组是Node
* */
5.LinkedHashMap
1.概念
遍历元素时,按照添加的顺序遍历的 在HashMap的基础上 增加了指针 频繁遍历时使用。
2.底层实现原理
* put 时调用的是Map的然后调用了 Map的putVal 然后调用了重写的的newNode
* 然后 Entry继承了父类的Node 并添加了 before和after属性 记录元素的添加记录
6.TreeMap
1.概念
主要用来排序 ,此时考虑key 的自然排序或者定制排序,底层是红黑树 和TreeList
2.TreeMap 自然排序和定制排序
注:只能按照key进行排序
@Test
public void te3(){
Map<String, Object> map = new TreeMap<>();
map.put("aa",119);
map.put("cc",110);
map.put("bb",110);
//1.自然排序 即实现Comparable接口
Set<Map.Entry<String, Object>> entries = map.entrySet();
for (Object o:
entries) {
System.out.println(o);
//aa=119
//bb=110
//cc=110
}
//2.定制排序 实现Comparator接口
Map<String, Object> map1 = new TreeMap<>(new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
if ( o1 instanceof String && o2 instanceof String){
String str1 = (String)o1;
String str2 = (String)o2;
// 加 - 号 是其相反的顺序 进行排序
return -str1.compareTo(str2);
}else {
throw new RuntimeException("类型不匹配");
}
}
});
map1.put("aa",119);
map1.put("cc",110);
map1.put("bb",110);
Set<Map.Entry<String, Object>> entries1 = map1.entrySet();
for (Object o:
entries1) {
System.out.println(o);
//cc=110
//bb=110
//aa=119
}
}
7. Map 的常用方法
@Test
public void te1(){
Map<String, Object> map = new HashMap<>();
Map<String, Object> map1 = new HashMap<>();
// V put(K key, V value); 添加一个键值对 如果key一样,返回值为上一个value 反之返回null
System.out.println(map.put("aa", 110));//null
System.out.println(map.put("aa", 120));//110
map1.put("aa",119);
map.put("bb",110);
System.out.println(map);//{aa=120}
// void putAll(Map<? extends K, ? extends V> m); 添加一个Map
map.putAll(map1);//{aa=120, bb=110}
// V remove(Object key); 返回remove里卖弄的value 不存在返回null
System.out.println(map.remove("aa")); //119
// void clear(); 清空数据 并不是删除此map对象
map.clear();
// V get(Object key); 返回其对应的value 不存在 返回null
System.out.println(map1.get("aa"));//119
// boolean containsKey(Object key); 是否包含指定的key boolean containsValue(Object value);是否包含指定的value
System.out.println(map1.containsKey("aa"));//true
System.out.println(map1.containsValue(119));//true
// boolean isEmpty();
System.out.println(map.isEmpty());//true
// int size(); 返回有几个键值对
System.out.println(map.size());//0
}
8. 遍历
@Test
public void te2(){
Map<String, Object> map = new HashMap<>();
map.put("aa",119);
map.put("bb",110);
map.put("cc",110);
//1.遍历所有的key Set<K> keySet();
Set<String> set = map.keySet();
for (Object s:
set) {
System.out.println(s);
//aa
//bb
//cc
}
// 2.遍历所有的value Collection<V> values(); 注意遍历key和value的白遍历顺序是一样的
Collection<Object> values = map.values();
for (Object o:
values) {
System.out.println(o);
//119
//110
//110
}
// 3.1遍历所有的key和value Set<Map.Entry<K, V>> entrySet();
Set<Map.Entry<String, Object>> entries = map.entrySet();
for (Object o:
entries) {
System.out.println(o);
//aa=119
//bb=110
//cc=110
}
// 3.2 遍历所有的key和value 用Iterator
Set<Map.Entry<String, Object>> entries1 = map.entrySet();
Iterator<Map.Entry<String, Object>> iterator = entries1.iterator();
while (iterator.hasNext()){
Object o = iterator.next();
// entrySet集合元素里面都是Entry
// Entry 是Map 里面定义的内部接口 里面有getKey() 和getValue() setValue(V value);
Map.Entry entry = (Map.Entry) o;
System.out.println(entry.getKey() + "-->" + entry.getValue());
//aa-->119
//bb-->110
//cc-->110
}
}
9.Properties
9.1概念
Properties的key和value都是String 主要用来处理属性文件
9.2代码实现
public class PropertiesTest {
// Properties的key和value都是String 主要用来处理属性文件
public static void main(String[] args) throws Exception {
Properties properties = new Properties();
// 通过IO流获取配置文件
FileInputStream fis = new FileInputStream("jdbc.properties");
properties.load(fis);
System.out.println(properties.getProperty("name"));
System.out.println(properties.getProperty("pwd"));
//admin
//123
// 流的关闭
fis.close();
}
}
jdbc.properties
注:不要有空格什么的,放在项目下,防止找不到文件
name=admin
pwd=123
三 Collections工具类
1.概念
Collections是用来操作Collection 和Map的一个工具类
2.一些常用的方法
@Test
public void te1(){
List list = new ArrayList();
list.add(8);
list.add(12);
list.add(23);
list.add(4);
System.out.println(list);//[8, 12, 23, 4]
// public static void reverse(List<?> list) 反转
Collections.reverse(list);
System.out.println(list);//[4, 23, 12, 8]
// public static void shuffle(List<?> list) 随机化
Collections.shuffle(list);
System.out.println(list);//无序 [12, 4, 8, 23]
// public static <T extends Comparable<? super T>> void sort(List<T> list) 此时按照的是Integer里面的Comparator方法
Collections.sort(list);
System.out.println(list);//[4, 8, 12, 23]
// public static void swap(List<?> list, int i, int j) 交换 list 里面的i和j元素
Collections.swap(list,1,3);
System.out.println(list);//[4, 23, 12, 8]
// public static <T extends Object & Comparable<? super T>> T max(Collection<? extends T> coll)
// public static <T extends Object & Comparable<? super T>> T min(Collection<? extends T> coll)
// 此时按照的是Integer里面的Comparator方法 的最大值和最小值
System.out.println(Collections.max(list));//23
System.out.println(Collections.min(list));//4
// public static int frequency(Collection<?> c, Object o) list集合里面 o出现了几次
System.out.println(Collections.frequency(list,12));//1
// public static <T> void copy(List<? super T> dest, List<? extends T> src)
// 注意源码中 if (srcSize > dest.size())
// throw new IndexOutOfBoundsException("Source does not fit in dest");
// 所以应该这样copy
List destList = Arrays.asList(new Object[list.size()]);
Collections.copy(destList,list);
System.out.println(destList);//[4, 23, 12, 8]
}
3.当涉及到线程安全时
提供了多个synchronized…的方法 使集合包装成线程同步的集合,从而解决多线程安全问题。