集合框架3
① Map集合
特点: 存储一对数据 (Key-Value),无序, 无下标, 键值不能重复, 值可以重复
方法 | 说明 |
---|---|
V put(K key, V value) | 将对象存入到集合当中,关联键值,key重复则覆盖原值 |
Object get(Object ket) | 根据键值取得对应的值 |
Sey<K> keySet() | 返回所有的key值的Set集合 |
Collection<V> values() | 返回所有value值的Collection集合 |
Set<Map.Entry<K,V>> entrySet() | 返回键值匹配的Set集合 |
boolean containsKey(Object key) | 判断集合中是否包含键值 |
boolean containsValue(Object value) | 判断集合中是否包含该value值 |
default boolean replace(K key,V oldValue, V newValue) | 指定键值替换value值 |
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
/**
* Map接口的使用
* 特点
* 1.存储的是键值对key-value
* 2.键值key不能重复,value值可以重复
* 3.无序
*/
public class MapSimple {
public static void main(String[] args) {
//创建Map集合
Map<String,String> map = new HashMap<>();
//1.添加元素
map.put("cn","中国");
map.put("uk","英国");
map.put("usa","美国");
//map.put("cn","ZhongGuo"); //键值相同时,后添加的数据会把之前添加的数据顶掉
System.out.println("元素个数:" + map.size()); //元素个数:3
System.out.println(map.toString()); //{usa=美国, uk=英国, cn=中国} {usa=美国, uk=英国, cn=ZhongGuo}
//2.删除元素 .remove(K key) .remove(K key,V value)
//3.遍历
//3.1 使用keySet()遍历 返回值是所有key的Set集合
// 增强for
for (String k : map.keySet()) {
System.out.println("key:" + k + " value:" + map.get(k));
}
//迭代器--推荐使用增强for
Iterator<String> it = map.keySet().iterator();
while(it.hasNext()){
String key = it.next();
System.out.println("key--" + key + " value--" + map.get(key));
}
//3.2 使用entrySet()方法遍历--效率相对较高
Set<Map.Entry<String, String>> entries = map.entrySet();
// 增强for
for (Map.Entry<String, String> entry : entries) {
System.out.println("key_" + entry.getKey() + " value_" + entry.getValue());
}
//4.判断
System.out.println(map.containsKey("uk")); //true
System.out.println(map.containsValue("日本")); //false
}
}
- Map集合的实现类
HashMap:
- JDK1.2版本实现,线程不安全,运行效率快
- 允许使用null作为key或是value
- 默认容量16,默认加载因子0.75
- 方法与Map接口中的方法一样
HashTable:
- JDK1.0提供,线程安全,运行效率慢
- 不允许null作为key或value
Properties:
- HashTable的子类
- 要求key和value都是String
- 通常用于配置文件的读取
TreeMap:
- 实现了SortedMap接口(是Map的子接口)
- 可以对Key进行自动排序
- HashMap的使用
HashMap:
- JDK1.2版本实现,线程不安全,运行效率快
- 允许使用null作为key或是value
- 默认容量16,默认加载因子0.75
- 方法与Map接口中的方法一样
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
/**
* HashMap的使用
* 存储结构:哈希表(数组+链表+红黑树)
* 使用key的hashcode()以及equals()的返回值作为存储去重的依据
*/
public class HashMapTest1 {
public static void main(String[] args) {
//创建聚合K,V
HashMap<Student,String> students = new HashMap<>();
//1.添加元素
Student s1 = new Student("iFinder",167);
Student s2 = new Student("Nancy",123);
Student s3 = new Student("BobJoy",213);
Student s4 = new Student("JackyChan",254);
students.put(s1,"云南");
students.put(s2,"北京");
students.put(s3,"美国");
students.put(s4,"英国");
//相同键值,不同value,会把旧的value顶掉
students.put(new Student("iFinder",167),"云南"); //如果不重写hashCode(),equals()方法,则默认会视为不同对象
//重写方法后,作为新建对象的参数传入无法成为新的集合元素
System.out.println("元素个数:" + students.size());
System.out.println(students.toString());
//2.删除 .remove(K k) .remove(K k,V value)
//3.遍历
//3.1使用kekSet()遍历
Set<Student> stuSet = students.keySet();
for(Student stu:stuSet){
System.out.println("key-" + stu.toString() + " value-" + students.get(stu));
}
//3.2使用entrySet()遍历
for(Map.Entry<Student,String> entry:students.entrySet()){
System.out.println("key: " + entry.getKey() + " value: " + entry.getValue());
}
//4.判断 .containsKey() .containsValue()
//在重写hashcode()方法和equals()方法之后可以将新建的对象作为参数传入实现判断
}
}
class Student{
private String name;
private int stuID;
//无参构造
public Student() {
}
//有参构造
public Student(String name, int stuID) {...}
public String getName() {...}
public void setName(String name) {...}
public int getStuID() {...}
public void setStuID(int stuID) {...}
@Override
public String toString() {
return "name-" + name + " stuID-" + stuID;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Student)) return false;
Student student = (Student) o;
return stuID == student.stuID && Objects.equals(name, student.name);
}
@Override
public int hashCode() {
return Objects.hash(name, stuID);
}
}
- HashMap源码分析
属性
- 初始容量: DEFAULT_INITIAL_CAPACITY 1<<4 (16)
- 最大容量: MAXMUM_CAPACITY 1<<30
- 加载因子: DEFAULT_LOAD_FACTOR 0.75f (元素数量到达百分之75,开始扩容)
- 树因子: TREEIFY_THRESHOLO 8(在链表长度大于8,数组长度大于等于64时,将链表改变成红黑树结构)
- 链表因子:UNTREEIFY_THRESHOLO 6(当红黑树元素小于6,调整为链表)
- 数组树因子:MIN_TREEIFT_CAPACITY 64
- transient Node<K,V,> table 哈希表中的数组
- size 元素的个数
构造方法
- 刚创建hashMap之后,没有赋值之前 table = null , size = 0.
添加第一个元素的时候size才为16(为了节省空间)public V put(K key, V value)方法
- return putVal(hash(key), key, value, false, true)
- hash(), 用来产生key的hash值
- 当元素个数大于阈值(16*0.75=12)时,扩容为原来大小的两倍
HashSet底层其实维护着一个HashMap.
- boolean add(E e)方法
return map.put(e, PRESENT) == null
- HashTable和Properties
HashTable:
- JDK1.0提供,线程安全,运行效率慢
- 不允许null作为key或value
Properties:
- HashTable的子类
- 要求key和value都是String
- 通常用于配置文件的读取
Properties可以保存到流中或从流中加载。 属性列表中的每个键及其对应的值都是一个字符串。
在IO流的学习中会详细学到Properties的使用
- TreeMap的使用
在类中实现Comparable接口
import java.util.Map;
import java.util.Objects;
import java.util.TreeMap;
public class TreeMapTest1 {
public static void main(String[] args) {
//创建集合
TreeMap<Student1,String> treeMap = new TreeMap<>();
//1.添加元素
Student1 s1 = new Student1("iFinder",167);
Student1 s2 = new Student1("Nancy",123);
Student1 s3 = new Student1("BobJoy",213);
Student1 s4 = new Student1("JackyChan",254);
//直接存储会报异常 java.lang.ClassCastException Student1 cannot be cast to class java.lang.Comparable
//需要提供比较的方法--实现comparable接口
treeMap.put(s1,"云南");
treeMap.put(s2,"北京");
treeMap.put(s3,"美国");
treeMap.put(s4,"英国");
System.out.println("元素个数: " + treeMap.size());
System.out.println(treeMap.toString()); //{name-Nancy stuID-123=北京, name-iFinder stuID-167=云南, name-BobJoy stuID-213=美国, name-JackyChan stuID-254=英国}
//实现接口后,报错消失,元素按规定的规则进行排列
//重写compareTo方法后,也可以实现将新建对象作为key传入去重的问题 但是value会替换为新的值
treeMap.put(new Student1("Nancy",123),"天津");
System.out.println(treeMap.toString()); //{name-Nancy stuID-123=天津, name-iFinder stuID-167=云南, name-BobJoy stuID-213=美国, name-JackyChan stuID-254=英国}
//2.删除 .remove(K key) .remove(K key,V value) .clear()
//3.遍历
//3.1 keySet()遍历
for(Student1 sut:treeMap.keySet()){
System.out.println("Key- " + sut.toString() + " Value- " + treeMap.get(sut));
}
//3.2 entrySet()遍历
for(Map.Entry<Student1,String> entry:treeMap.entrySet()){
System.out.println("Key: " + entry.getKey() + " Value: " + entry.getValue());
}
//4.判断 .containsKey() .containsValue()
}
}
class Student1 implements Comparable<Student1>{
private String name;
private int stuID;
//无参构造
public Student1() { }
//有参构造
public Student1(String name, int stuID) {...}
public String getName() {...}
public void setName(String name) {...}
public int getStuID() {...}
public void setStuID(int stuID) {...}
@Override
public String toString() {...}
@Override
public int compareTo(Student1 o) {
//按学号大小进行排序
int n1 = this.stuID - o.getStuID();
return n1;
}
}
定制比较
import java.util.Comparator;
import java.util.TreeMap;
/**
* 比较器定义比较方式
*/
public class TreeMapTest2 {
public static void main(String[] args) {
TreeMap<Student2,String> treeMap = new TreeMap<>(new Comparator<Student2>() {
@Override
public int compare(Student2 o1, Student2 o2) {
int n1 = o1.getStuID() - o2.getStuID();
return n1;
}
});
//1.添加元素
Student2 s1 = new Student2("iFinder",167);
Student2 s2 = new Student2("Nancy",123);
Student2 s3 = new Student2("BobJoy",213);
Student2 s4 = new Student2("JackyChan",254);
//直接存储会报异常 java.lang.ClassCastException Student1 cannot be cast to class java.lang.Comparable
//定制比较,将定制比较对象作为参数传入
treeMap.put(s1,"云南");
treeMap.put(s2,"北京");
treeMap.put(s3,"美国");
treeMap.put(s4,"英国");
System.out.println("元素个数: " + treeMap.size());
System.out.println(treeMap.toString()); //{name-Nancy stuID-123=北京, name-iFinder stuID-167=云南, name-BobJoy stuID-213=美国, name-JackyChan stuID-254=英国}
//定制比较后,报错消失,元素按规定的规则进行排列
//定义定制比较后,也可以实现将新建对象作为key传入去重的问题 但是value会替换为新的值
treeMap.put(new Student2("Nancy",123),"天津");
System.out.println(treeMap.toString()); //{name-Nancy stuID-123=天津, name-iFinder stuID-167=云南, name-BobJoy stuID-213=美国, name-JackyChan stuID-254=英国}
}
}
class Student2{
private String name;
private int stuID;
//无参构造
public Student2() { }
//有参构造
public Student2(String name, int stuID) {...}
public String getName() {...}
public void setName(String name) {...}
public int getStuID() {... }
public void setStuID(int stuID) {...}
@Override
public String toString() {...}
}
TreeSet与TreeMap的关系
- TreeSet底层维护一个TreeMap
TreeSet(){
this(new TreeMap<E, Object>()) }
add(){
return m.put(e, PRESENT) == null }
②Collections工具类
概念:Collections是集合的工具类,定义了除了存取以外的集合常用方法
方法 | 说明 |
---|---|
public static void reverse(List<?> list) | 反转集合中元素的顺序 |
public static void shuffle(List<?> list) | 随机重置集合元素的顺序 |
public static void sort(List<?> list) | 升序排序(元素必须实现Comparable接口) |
static <T> int binarySearch(List<? extends Comparable<? super T>> list, T key) | 使用二分查找搜索指定列表,获得指定对象 |
static <T> void copy(List<? super T> dest, List<? extends T> src) | 将一个元素从一个列表复制到另一个列表 |
package com;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class CollectionsTool {
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
//添加数据
int[] in = {20,5,12,30,6,18};
for (int i : in) {
list.add(i);
}
//1.排序
System.out.println(list.toString()); //[20, 5, 12, 30, 6, 18]
Collections.sort(list);
//Collections.sort(List<> list, Comparator<> ...); 可以定制排序比较的方法
System.out.println(list.toString()); //[5, 6, 12, 18, 20, 30]
//2.binarySearch() 二分查找
int i = Collections.binarySearch(list,30);
System.out.println(i); //如果找到 i >= 0(元素位置) 没找到返回 -1
//3.拷贝 copy()
List<Integer> dest = new ArrayList<>();
for (int i1 = 0; i1 < list.size(); i1++) {
dest.add(0);
}
Collections.copy(dest,list); //直接copy会报错,需要将二者的大小设置为相同
System.out.println(dest); //添加空数据后copy成功
//4.反转 reverse()
Collections.reverse(list);
System.out.println(list); // [30, 20, 18, 12, 6, 5]
//5.打乱 shuffle();
Collections.shuffle(list);
System.out.println(list); //[18, 12, 5, 30, 20, 6]
Collections.shuffle(list);
System.out.println(list); //[5, 18, 6, 20, 30, 12]
//6.将集合转为数组
Integer[] arr= list.toArray(new Integer[10]); //[]中的长度需要小于list长度,大于list长度,多出来的容量为空
System.out.println(arr.length);
System.out.println(Arrays.toString(arr)); //[18, 12, 30, 5, 20, 6, null, null, null, null]
//7.将数组转为集合
String[] names = {"iFinder","Nancy","BobJoy"};
List<String> list1 = Arrays.asList(names); //受限集合,不能添加和删除元素 因为数组长度固定,新建后不能改变长度
//list1.remove(1); java.lang.UnsupportedOperationException
System.out.println(list1.toString()); //[iFinder, Nancy, BobJoy]
//特例: 基本类型集合转为集合组要转为包装类
//int[] nums = {100,200,300,400};
Integer[] nums = {100,200,300,400};
List<Integer> list2 = Arrays.asList(nums);
}
}
③集合总结
- 集合的概念:
集合是对象的容器,和数组类似,定义了对多个对象进行操作的常用方法- List集合
有序、有下标、元素可以重复(ArrayList–数组、LinkedList–双向链表、Vector)- Set集合
无序、无下标、元素不可以重复(HashSet–哈希表、TreeSet–红黑树)- Map集合
存储一对数据,无序、无下标,键值不可以重复,值可以重复- Collections工具
集合的工具类,定义了除了存取以外的集合的常用方法