java学习-Set和Map集合
1. Set集合
1.1 Set集合介绍
- Set集合Collection集合的一个子接口
- Set集合特点:
1) 元素存取无序 : 存储Set集合元素的顺序与从Set集合中取出元素的顺序不能保证一致
2) 无索引 : Set集合中的每一个元素没有索引位置
3) 去重复 : Set集合中不存储重复的元素
3.Set接口,不能实例化对象, 找到实现类HashSet, 哈希表数据结构
Set<E> set = new HashSet<>();
代码
public class Demo01_Set集合介绍 { public static void main(String[] args) { Set<String> set = new HashSet<>(); set.add("999"); set.add("999"); set.add("a"); set.add("Hello"); set.add("a"); set.add("a"); System.out.println(set);//[a, Hello, 999] } }
1.2 Set集合遍历
- toArray() : 将集合中的元素转换到一个Object[] 类型数组中
- toArray(T[] arr) : 集合转数组; 但是列表中需要提供一个与集合数据类型相同的数组类型参数, 将集合中元素同步到参数数组中, 这个数组具有指定类型, 遍历数组时候不需要向下转型; 如果arr数组大小不够集合中的元素个数, toArray方法会为你生成一个新的T[]作为方法的返回; 返回值类型T[]
- 迭代器
- 增强for(forEach) :
1) forEach语句结构:
for( 元素数据类型 变量名 : 需要遍历的集合或者数组 ){
}
2) 说明 :
a : 元素数据类型 : 表示需要遍历的这个集合或者数组中的元素具有的数据类型
b : 变量名 : 表示集合或者数组中的每一个元素
3) 注意 :
a : 增强for 语法底层是使用了迭代器的遍历原理
b : 使用增强for有可能会发生并发修改异常
代码
public class Demo02_Set集合遍历1 { public static void main(String[] args) { Set<String> set = new HashSet<>(); set.add("999"); set.add("a"); set.add("Hello"); Object[] objArr = set.toArray(); for(int index = 0; index < objArr.length; index++) { Object obj = objArr[index]; String s = (String)obj; System.out.println(s); } } }
public class Demo03_Set集合遍历2 { public static void main(String[] args) { Set<String> set = new HashSet<>(); set.add("999"); set.add("a"); set.add("Hello"); String[] a = new String[set.size()]; set.toArray(a); for(int index = 0; index < a.length; index++) { String s = a[index]; System.out.println(s); } } }
public class Demo04_Set集合遍历3 { public static void main(String[] args) { Set<String> set = new HashSet<>(); set.add("999"); set.add("a"); set.add("Hello"); Iterator<String> it = set.iterator(); while(it.hasNext()) { String s = it.next(); System.out.println(s); } } }
public class Demo05_Set集合遍历4 { public static void main(String[] args) { Set<String> set = new HashSet<>(); set.add("999"); set.add("a"); set.add("Hello"); /*for( 元素数据类型 变量名 : 需要遍历的集合或者数组 ){ }*/ for(String s : set) { System.out.println(s); set.add("world"); } } }
1.3HashSet保证元素唯一原理
1.3.1 HashSet存储JDK提供类型
HashSet存储JDK提供的类型时, 可以保证元素存储是去重复的
1.3.2 HashSet存储自定义类型
- 自定义的类Person, Person中具有name和age属性, 如果Person的姓名和年龄都相同,认为这是重复的数据,需要HashSet进行去重复存储
- 设计好了Person类型之后,将多个Person对象存储在HashSet中, 发现没有给自定义类型进行去重复
- 认为与HashSet中add方法的实现有关, add方法中, 使用了hashCode() 和equals() 方法
- 试着将hashCode() 和equals() 方法在Person类型中重写, alt + shift + s , 重写后,去重复成功
- 总结 : 自定义类型重写hashCode() 和equals() 方法,保证在HashSet中存储元素唯一
代码
ublic class Person { private String name; private int age; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public Person(String name, int age) { super(); this.name = name; this.age = age; } public Person() { super(); } @Override public String toString() { return "Person [name=" + name + ", age=" + age + "]"; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + age; result = prime * result + ((name == null) ? 0 : name.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Person other = (Person) obj; if (age != other.age) return false; if (name == null) { if (other.name != null) return false; } else if (!name.equals(other.name)) return false; return true; } }
public class Demo07_HashSet存储自定义Person { public static void main(String[] args) { // 要求 : 如果人员信息, 姓名和年龄都相同,认为Person重复数据 HashSet<Person> set = new HashSet<>(); set.add(new Person("张三",20)); set.add(new Person("李四",20)); set.add(new Person("张三",20)); System.out.println(set);//[Person [name=李四, age=20], Person [name=张三, age=20]] } }
1.3.3 hashCode方法
- hashCode方法来自于Object类型中, 可以被所有类继承使用
- hashCode源代码在Object中功能: 比较对象是否是同一个
1) 求对象的哈希码值, 将一个对象在内存中的地址转换成一个整数结果, 这个整数就称为对象的哈希码值
2) 不同的对象计算出不同的整数(哈希码值), 因为整数结果不同,验证对象是否是同一个
3.hashCode计算规则:
1) 同一对象多次调用 hashCode 方法时,必须一致地返回相同的整数
2) equals(Object) 方法,两个对象是相等的,那么对这两个对象中的每个对象调用 hashCode 方法都必须生成相同的整数结果
3) equals(Object) 方法,两个对象是不相等的, 那么对这两个对象中的每个对象调用 hashCode 方法整数结果尽量不相同
4.实际开发中, 比较两个对象的地址没有意义, 通过在子类中重写hashCode方法, 重写之后,比较的就是对象中的成员变量对应的hashCode值是否相等
1.3.4 LinkedHashSet
- LinkedHashSet是HashSet的一个子类, 子类中方法与HashSet中的方法一样, 同样也可以保证元素的唯一性
- LinkedHashSet 底层结构 : 双向链表, 能够保证添加进入到集合中的元素与从集合中取出的元素顺序一致,保证迭代顺序
代码
public class Demo08_LinkedHashSet { public static void main(String[] args) { LinkedHashSet<String> linkSet = new LinkedHashSet<>(); linkSet.add("999"); linkSet.add("Hello"); linkSet.add("a"); System.out.println(linkSet);//[999, Hello, a] HashSet<String> set = new HashSet<>(); set.add("999"); set.add("Hello"); set.add("a"); System.out.println(set);// [a, Hello, 999] } }
2. Map集合
2.1 Map集合的介绍
- Map是双列集合顶层父接口, 来自于java.util包
Map<K,V> : 描述的键值对映射关系, 一对一 , 一个Key的值对应1个Value
K-----Key 键
V----Value 值
2.map类比记忆 : map英文中表示地图概念, 地图上的每一个点都对应现实生活中的一个地理位置, 将地图一对一的关系类比成Map集合
3.Map集合的存储特点:
1) Map集合中, Key值不重复(唯一)
2) Map集合中, Value值可以重复
通常对于Map集合的操作,使用唯一的Key值操作对应的Value的值
4.Map接口, 不能实例化对象, 需要实现类, HashMap--->哈希表结构
2.2 Map集合中的常用方法
- put(K key, V vlue):
1) 如果添加的key值在Map集合中不存在, 那么表示添加功能, 将键值对映射关系添加到Map集合中, 方法返回值类型V--->value
2) 如果添加的key值在Map集合中已经存在, 那么表示修改功能, 修改(覆盖)指定key对应的value值
2.remove(Object key) : 将Map集合中指定key值所对应的键值对映射关系删除, 返回值是value值
3.clear() : 清空Map集合中的所有元素
4.size() : 获取Map集合中的键值对数量
5.get(Object key) : 通过Map集合中的key值, 获取到对应的value
6.containsKey(Object k) : 验证Map集合的key中,是否包含参数k, 包含返回true, 不包含返回false, 返回值类型boolean
7.containsValue(Object v) : 验证Map集合的value值中,是否包含参数v, 包含返回true, 不包含返回false, 返回值类型boolean
代码
public class Demo01_Map集合常用方法 { public static void main(String[] args) { Map<Integer, String> map = new HashMap<Integer, String>(); // 1. put(K key, V vlue):如果添加的key的值在Map集合中不存在, 那么表示添加功能, // 将键值对映射关系添加到Map集合中, 方法返回值类型V--->value map.put(11, "a"); map.put(12, "b"); map.put(13, "a"); System.out.println(map);// {11=a, 12=b, 13=a} System.out.println(map.size());// 3 // 2.put(K key, V vlue):如果添加的key的值在Map集合中已经存在, 那么表示修改功能, 修改(覆盖)指定key对应的value值 map.put(12, "new"); System.out.println(map);// {11=a, 12=new, 13=a} // 3. remove(Object key) : 将Map集合中指定key值, 键值对映射关系删除, 返回就是value值 String value = map.remove(12); System.out.println(value);// new System.out.println(map);// {11=a, 13=a} // 4. clear() : 清空Map集合中的所有元素(成对) /*map.clear(); System.out.println(map);//{} // 5. size() : 获取Map集合中的键值对数量 System.out.println(map.size());// 0 */ // 6. get(Object key) : 通过Map集合中的key的值, 获取到对应的value String value1 = map.get(13); System.out.println(value1);// a // 7.containsKey(Object k) : 验证Map集合的key中,是否包含参数k, 包含返回true, 不包含返回false, 返回值类型boolean System.out.println(map.containsKey(11));// true System.out.println(map.containsKey(12));// false // 8.containsValue(Object v) : 验证Map集合的value值中,是否包含参数v, 包含返回true, 不包含返回false, 返回值类型boolean System.out.println(map.containsValue("a"));// true System.out.println(map.containsValue("b"));// false } }
2.3Map集合的第一种遍历keySet(掌握)
- keySet() : 将Map集合中的所有的Key值获取到, 放置到一个Set集合中
- 遍历含有Key值的Set集合, 获取到每一个Key值, 然后通过get(Key), 通过每一个Key值获取到齐对应的Value值
代码
public class Demo02_Map第一种遍历KetSet { public static void main(String[] args) { Map<Integer, String> map = new HashMap<Integer, String>(); map.put(11, "a"); map.put(13, "a"); map.put(12, "b"); // 1. 获取到map中的所有的key的值 Set<Integer> setK= map.keySet(); // 2. 遍历setK获取到每一个Key值 for(Integer key : setK) { // 3. 通过get方法获取对应的value值 String value = map.get(key); System.out.println(key + "-----" + value); } Iterator<Integer> it = setK.iterator(); while(it.hasNext()) { Integer key1 = it.next(); String value1 = map.get(key1); System.out.println(key1 + "*******" + value1); } } }
2.4 Map集合的第二种遍历entrySet(掌握)
greregegr你
1.entrySet() : 将Map集合中的所有的键值对关系获取到(成对的数据), 放置到一个Set集合中, Map集合中的每一对数据就是Map.Entry<K,V>类型
2.遍历装有Map.Entry<K,V>键值对类型的Set集合, 获取到每一对关系
3.在Map.Entry<K,V>类型中, 有方法能单独获取到一对元素中的key和value
1) getKey() : 获取到键值对中key值, 返回值类型K
2) getValue() : 获取到键值对中key值, 返回值类型V
代码
public class Demo03_Map第二中遍历EntrySet { public static void main(String[] args) { Map<Integer, String> map = new HashMap<Integer, String>(); map.put(11, "a"); map.put(13, "a"); map.put(12, "c"); // 1. 获取到Map集合中所有键值对数据 Set<Map.Entry<Integer, String>> set = map.entrySet(); // 2. 遍历set集合, 将每一对映射关系获取到 for(Map.Entry<Integer, String> entry: set) { // 3. 获取到一对关系中的key和value Integer key = entry.getKey(); String value = entry.getValue(); System.out.println(key + "?????" + value); } } }
2.5 HashMap
- HashMap : Map双列集合实现类, 底层哈希表结构
- HashMap 集合对于元素的存取无序, Map集合没有索引
- HashMap集合中的key值唯一, 保证key值不重复实现原理与HashSet一致
1) 如果HashMap存储JDK提供类型作为key, 直接保证key不重复
2) 如果HashMap存储自定义的类型作为key, 要求自定义类型中重写hashCode和equals两个方法
代码
public class Person { private String name; private int age; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public Person(String name, int age) { super(); this.name = name; this.age = age; } public Person() { super(); // TODO Auto-generated constructor stub } @Override public String toString() { return "Person [name=" + name + ", age=" + age + "]"; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + age; result = prime * result + ((name == null) ? 0 : name.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Person other = (Person) obj; if (age != other.age) return false; if (name == null) { if (other.name != null) return false; } else if (!name.equals(other.name)) return false; return true; } }
public class Demo04_HashMap存储自定义类型 { public static void main(String[] args) { HashMap<Person, String> map = new HashMap<>(); map.put(new Person("zs",19), "新加坡"); map.put(new Person("lis",20), "香港"); map.put(new Person("zs",19), "北京"); System.out.println(map); } }
2.6 LinkedHashMap
- LinkedHashMap 是HashMap的子类, 方法功能与HashMap一致, 但是LinkedHashMap维护了双向链表, 效果 : 保证元素的迭代顺序 (元素的存取顺序一致)
代码
package com.ujiuye.map; import java.util.HashMap; import java.util.LinkedHashMap; public class Demo05_LinkedHashMap { public static void main(String[] args) { HashMap<Integer, String> map = new HashMap<Integer, String>(); map.put(11, "a"); map.put(13, "a"); map.put(12, "c"); System.out.println(map);// {11=a, 12=c, 13=a} LinkedHashMap<Integer, String> map1 = new LinkedHashMap<Integer, String>(); map1.put(11, "a"); map1.put(13, "a"); map1.put(12, "c"); System.out.println(map1);// {11=a, 13=a, 12=c} } }