Java集合
编辑时间:2021/03/23
读完本节:大概花费40钟,共3530词
文章目录
1.集合Collection中存储自定义对象的注意事项
- 对于List存储自定义对象需要重写equals()方法,删除元素、修改元素、插入元素时需要用到自定义类中的equals()方法确定是否存在元素,然后才是执行操作
- 对于Set分两种情况:
- 对于Set的HashSet、LinkedHashSet实现类,需要重写equals()、hashCode()方法,原因同上。
- 对于Set的TreeSet实现类,需要实现Comparable接口中的compareTo(Object obj)或者Comparator接口中的compare(Object o1, Object o2)
2.Java集合之Map接口
-
Map接口继承树:
-
Map接口:存储双列数据,存储的时key-value对的数据。
-
Map接口有三个实现类:HashMap、TreeMap、Hashtable。
-
HashMap有一个子类LinkedHashMap底层使用链表方式支持;Properties是Hashtable的一个子类,其key和value都是String类型
-
HashMap的底层,在JDK1.7及之前运用了数组+链表;在JDK1.8后运用数组+链表+红黑树
-
Map中的key是无序的、不可重复的,使用Set从存储所有的key,key所在的类需要重写equals()方法和hashCode()方法;Map中的value也是无序的,但可以重复,使用Collection存储所有的value,同样的value所在的类也需要重equals()方法;一个key-value键值对构成了一个Entry对象;Map中的Entry是无序的、不可重复的,使用Set存储所有的Entry
-
Map接口常用的方法:
-
添加、删除、修改操作:
-
Object put(Object key, Object value):将指定的key-value添加到(或修改)到当前map对象中
-
void putAll(Map m):将m中所有的key-value键值对存放到当前Map中
-
Object remove(Object key):移除指定key的key-value键值对,并返回value
-
void clear():清空当前map中的所有数据
import org.junit.Test; import java.util.HashMap; import java.util.Map; /** * @Author: xuehai.XUE * @MailBox: xuehai.xue@qq.com * @Date: 2021/3/23 19:32 * @Description: */ public class MapMethodTest { @Test public void test(){ //因为Map是一个接口,其中定义的方法都是抽象方法, //因此通过实现类HashMap来展示Map中定义的功能 Map map = new HashMap(); //添加 map.put("AA",123); map.put(456,123); map.put("BB",567); //修改 map.put("AA",97); System.out.println(map); Map map1 = new HashMap(); map1.put("CC",123); map1.put("DD",123); map.putAll(map1); System.out.println(map); //remove(Object obj) Object value = map.remove("CC"); System.out.println(value); System.out.println(map); //clear() map.clear();//与map = null操作不同 System.out.println(map.size()); System.out.println(map); } }
-
-
元素查询操作:
-
Object get(Object key):获取指定key对应的value
-
boolean containsKey(Object key):是否包含指定的key
-
boolean containsValue(Object value):是否包含指定的Value
-
int size():返回map中key-value键值对的个数
-
boolean isEmpty():判断当前map是否为空
-
boolean equals(Object obj):判断当前map和参数对象obj是否相等
import org.junit.Test; import java.util.HashMap; import java.util.Map; /** * @Author: xuehai.XUE * @MailBox: xuehai.xue@qq.com * @Date: 2021/3/23 19:32 * @Description: */ public class MapMethodTest { @Test public void test1(){ Map map = new HashMap(); map.put("AA",123); map.put(456,123); map.put("BB",567); //找到返回value没找到返回null System.out.println(map.get(456)); } }
-
-
元视图的操作方法:
-
Set keySet():返回所有key构成的Set集合
-
Collection values():返回所有value构成的Collection集合
-
Set entrySet():返回所有key-value键值对的构成的Set集合
import org.junit.Test; import java.util.*; /** * @Author: xuehai.XUE * @MailBox: xuehai.xue@qq.com * @Date: 2021/3/23 19:32 * @Description: */ public class MapMethodTest { @Test public void test2(){ Map map = new HashMap(); map.put("AA",123); map.put(456,123); map.put("BB",567); //遍历所有的key集 Set set = map.keySet(); Iterator iterator = set.iterator(); while(iterator.hasNext()){ System.out.println(iterator.next()); } System.out.println("*****************"); //遍历所有的value集 Collection values = map.values(); //方式1:采用增强for循环 for(Object obj : values){ System.out.println(obj); } //遍历所有的key-value //方式一:使用entrySet() Set entrySet = map.entrySet(); Iterator iterator1 = entrySet.iterator(); while (iterator1.hasNext()){ Object obj = iterator1.next(); //entrySet集合中的元素都是entry Map.Entry entry = (Map.Entry) obj; System.out.println(entry.getKey() + "----" + entry.getValue()); } System.out.println("*****************"); //使用keySet和values配合完成遍历所有的key-value Set keySet = map.keySet(); Iterator iterator2 = keySet.iterator(); while (iterator2.hasNext()){ Object key = iterator2.next(); Object value = map.get(key); System.out.println(key + "====" + value); } } }
-
-
Map常用方法小结:
- 添加:put(Object key, Object value)
- 删除:remove(Object key)
- 修改:put(Object key, Object value)
- 查询:get(Object key)
- 长度:size()
- 遍历:keySet() / values() / entrySet()
-
3.Map实现类之HashMap
- HashMap是Map接口中使用频率最高的实现类
- HashMap允许使用null键和null值,与HashSet一样的是,HashMap不能保证映射的顺序
- 所有的key构成的集合是Set,这个Set集合是无序的、不可重复的。所以key所在的类要重写:equals()方法和hashCode()方法
- 所有的value构成的集合是Collection,这个Collection是无序的、可以重复的。所以value所在的类要重写:equals()方法
- 一个键值对构成一个entry,所有的entry构成的集合Set是无序的、不可重复的
- HashMao判断两个key相等的标准是:两个key通过equals返回true,且hashCode值也相等
- HashMap判断两个value相等的标准是:两个value通过equals()方法返回true
- HashMap虽然是线程不安全的,但是提高了效率
4.HashMap底层实现原理
-
在JDK1.7中和JDK1.8中HashMap底层实现原理略有不同
-
HashMap的底层实现原理(JDK1.7环境下):
-
HashMap的实例化过程:
HashMap map = new HashMap()
在实例化完成后,底层创建了一个长度是16的一维数组Entry[] table
-
图示HashMap添加元素的过程:
对于第第二个和第三个判断,其中的key1-value1和原来的数据以链表的方式存储
-
HashMap在元素的添加过程中,底层数组的扩容机制
在向HashMap中不断添加数据的过程中,会涉及扩容问题,当超出临界值(且要存放的位置非空时),扩容为原来容量的两倍(resize(newCapacity * table.length)),并将原有的数据复制到新的Entry[] table数组中。
-
HashMap底层源码(JDK1.7)
-
-
HashMap在JDK1.8中与JDK1.7中底层实现原理的差异
-
new HashMap():实例化HashMap时,底层没有立刻实例化一个长度为16的数组
-
在JDK1.8中,底层数组使用的时Node[] 而非Entry[]
-
在首次调用HashMap的put方法时,底层才创建一个长度为16的Node[]数组
-
JDK1.7底层结构只有:数组+链表;JDK1.8底层结构是:数组+链表+红黑树
- 当满足数组的某一个索引位置上的元素以链表形式存在的数据个数,即链表长度超过8;且当前数组的长度大于64时,此时索引位置上的所有数据改为使用红黑树存储
-
JDK1.8环境下HashMap的底层源码
-
5.HashMap中重要的常量
- DEFAULT_INITIAL_CAPACIRY:HashMap的默认容量16
- MAXIMUM_CAPACIRY:HashMap最大支持容量1^30
- DEFAULT_LOAD_FACTOR:HashMap默认加载因子 0.75
- TREEIFY_THRESHOLD:Bucket中链表长度大于该默认值,则将链表转换为红黑树 8
- UNTREEIFY_THRESHOLD:Bucket中红黑树存储的Node小于该默认值,转换为链表
- MIN_TREEIFY_CAPACITY:桶中的Node被树化时最小的hash表容量。64(当桶中Node的数量大到需要转换为红黑树时,若hash表容量小于MIN_TREEIFY_CAPACITY时,此时应执行resize扩容操作,这个MIN_TREEIFY_CAPACITY的值至少是TREEIFY_THRESHOLD的4倍)
- table:存储元素的数组,总是2的n次幂
- entrySet:存储具体元素的集
- size:HashMap中存储的键值对的数量
- modCount:HashMap扩容和改变结构的次数
- threshold:扩容的临界值,等于“容量*填充因子”
- loadFactor:填充因子
6.HashMap子类LinkedHashMap
- LinkedHashMap中定义的内部类与HashMap中定义的内部类不同,HashMap中定义的内部类是Node,LinkedHashMap定义的内部类是Entry,LinkedHashMap定义的Entry内部类,它与HashMap不同的是LinkedHashMap维护了一个贯穿其所有条目的双向链表。这个链表定义了遍历顺序,通常是插入map中的顺序
- LinkedHashMap继承于HashMap,实现了Map接口,重写了父类HashMap中的newNode方法
- 对于频繁的遍历操作,此类执行效率高于HashMap,但是其他的操作(直接向数组中插入元素等)HashMap的效率要更高
7.LinkedHashMap底层实现先后顺序的原理
-
其中的before和after用于记录添加元素的先后顺序
8.HashSet在底层添加元素时的过程
-
HashSet在底层添加元素时,实际上是将元素放入HashMap中的一个key中,且该key指向的是一个Object对象
9.Map实现类之TreeMap
-
保证按照添加的key-value对进行排序,实现遍历排序,此时需要考虑实现Comparable接口中的compareTo(Object obj)方法,或者实现Comparator中的compare(Object o1, Object o2)方法,即考虑key的自然排序或者定制排序;TreeMap底层采用红黑树实现
import org.junit.Test; import java.util.Comparator; import java.util.Iterator; import java.util.Set; import java.util.TreeMap; /** * @Author: xuehai.XUE * @MailBox: xuehai.xue@qq.com * @Date: 2021/3/23 20:02 * @Description: */ public class TreeMapTest { /** 定制排序 */ @Test public void test2(){ TreeMap map = new TreeMap(new Comparator() { @Override public int compare(Object o1, Object o2) { if(o1 instanceof User && o2 instanceof User){ User u1 = (User)o1; User u2 = (User)o2; return -Integer.compare(u1.getId(),u2.getId()); } throw new RuntimeException("输入的类型不匹配!"); } }); User u1 = new User("Genji", 1); User u2 = new User("Hana", 2); User u3 = new User("Zenyatta", 3); User u4 = new User("Maccree", 4); User u5 = new User("Ashe", 5); map.put(u1,200); map.put(u2,500); map.put(u3,200); map.put(u4,200); map.put(u5,200); Set set = map.keySet(); Iterator iterator = set.iterator(); while(iterator.hasNext()){ System.out.println(iterator.next()); } } /** 自然排序 */ @Test public void test1(){ TreeMap map = new TreeMap(); User u1 = new User("Genji", 1); User u2 = new User("Hana", 2); User u3 = new User("Zenyatta", 3); User u4 = new User("Maccree", 4); User u5 = new User("Ashe", 5); map.put(u1,200); map.put(u2,500); map.put(u3,200); map.put(u4,200); map.put(u5,200); Set set = map.keySet(); Iterator iterator = set.iterator(); while(iterator.hasNext()){ System.out.println(iterator.next()); } } }
import java.util.Objects; /** * @Author: xuehai.XUE * @MailBox: xuehai.xue@qq.com * @Date: 2021/3/22 19:05 * @Description: */ public class User implements Comparable{ private String name; private int id; public User() { } public User(String name, int id) { this.name = name; this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getId() { return id; } public void setId(int id) { this.id = id; } @Override public String toString() { return "User{" + "name='" + name + '\'' + ", id=" + id + '}'; } @Override public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof User)) return false; User user = (User) o; return getId() == user.getId() && Objects.equals(getName(), user.getName()); } @Override public int hashCode() { return Objects.hash(getName(), getId()); } /** 输入的性名按照从大到小的顺序排列 */ @Override public int compareTo(Object o){ if(o instanceof User){ User user = (User)o; return -this.name.compareTo(user.name); }else{ throw new RuntimeException("输入的类型不匹配"); } } }
10. Map实现类之Properties
-
Properties是Hashtable的子类,该对象用于处理属性文件
-
由于属性文件里的key、value都是字符串类型,所以Properties里的key和value都是字符串类型
-
存取数据时,通常使用setProperty(String key, String value)方法和getProperty(String key)方法
import java.io.FileInputStream; import java.io.IOException; import java.util.Properties; /** * @Author: xuehai.XUE * @MailBox: xuehai.xue@qq.com * @Date: 2021/3/23 20:23 * @Description: */ public class PropertiesTest { public static void main(String[] args) { Properties pro = new Properties(); FileInputStream fis = null; try { fis = new FileInputStream("jdbc.properties"); pro.load(fis); String name = pro.getProperty("name"); String pwd = pro.getProperty("password"); System.out.println("name = " + name + ", password = " + pwd); } catch (IOException e) { e.printStackTrace(); }finally { if(fis != null){ try { fis.close(); } catch (IOException e) { e.printStackTrace(); } } } } }
name=biggy password=962469
11.HashMap、TreeMap、Hashtable三者的区别
- HashMap:作为Map的主要实现类;线程不安全,但效率高;能够存储null值的key和value;底层在JDK1.7采用数组+链表,JDK1.8采用数组+链表+红黑树
- TreeMap:保证按照添加键值对的顺序进行排序,实现排序遍历;底层的比较不使用equals()方法和hashCode()方法,而是实现Comparable接口中的compareTo(Object obj)方法,或实现Comparator中的compare(Object o1, Object o2)方法。
- Hashtable:作为古老的Map实现类,虽然线程安全,但是效率低;不能存储null值的key和value
12.Collections工具类
-
类似于Arrays工具类,Collections是一个操作List、Set和Map等集合的工具类
-
Collections中提供了一系列的静态方法,这些方法可以对集合元素进行排序、查询、和修改等操作
-
常用操作:
-
排序操作(均为static):
- reverse(List):反转List中的元素
- shuffle(List):对List集合元素进行随机排序
- sort(List):根据元素的自然顺序对指定List集合元素按升序排列
- sort(List, Comparator):根据指定的Comparator产生的顺序对List集合元素进行排序
- swap(List, int i, int j):将指定List集合中的i处元素和j处元素进行交换
-
查找、替换
- Object max(Collection):根据元素的自然排序,返回指定集合中最大的元素
- Object min(Collection):根据元素的自然排序,返回指定集合中最小的元素
- Object max(Collection, Comparator):根据Comparator指定的顺序,返回给定集合中最大的元素
- Object min(Collection, Comparator):根据Comparator指定的顺序,返回给定集合中最小的元素
- int frequency(Collection, Object):返回指定集合中指定元素出现的频率(次数)
- void copy(List dest, List src):将src中的内容复制到dest中
- boolean replaceAll(List list, Object oldVal, Object newVal):使用新值替换List对象中所有的旧值
-
同步控制
- Collections类中提供了多个synchronizedXxx()方法,该方法可以将指定集合包装成线程同步的集合,从而可以解决多线程并发访问集合时的线程安全问题(ArrayList、LinkedArrayList、HashSet、LinkedHashSet、HashMap、LinkedHashMap等)
import org.junit.Test; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; /** * @Author: xuehai.XUE * @MailBox: xuehai.xue@qq.com * @Date: 2021/3/23 20:58 * @Description: */ public class CollectionsTest { @Test public void test(){ List list = new ArrayList(); list.add(123); list.add(451); list.add(485); list.add(0); list.add(-516); list.add(98); System.out.println(list); //报异常:java.lang.IndexOutOfBoundsException: Source does not fit in dest // List dest = new ArrayList(); //正确写法:创建相同长度的null值List dest List dest = Arrays.asList(new Object[list.size()]); System.out.println(dest); Collections.copy(dest, list); System.out.println(dest); //返回的list1即为线程安全的list List list1 = Collections.synchronizedList(list); } }
-