JAVA学习笔记之Map&Set
1.HashSet集合
1.1Set接口的特点
1.无序:存入集合的顺序与取出集合的顺序不一致
2.没有索引
3.元素唯一:存入集合的元素没有重复
1.2案例
//创建set集合对象
Set<String > set = new HashSet<String>();
//添加数据
set.add("java");
set.add("php");
set.add("python");
//遍历集合对象
/**
* set对象可以通过三张方法遍历集合
* 转数组
* 迭代器
* 增强for循环
*/
//转数组:
Object[] objects = set.toArray();
for (int i = 0; i < objects.length ; i++) {
System.out.println(objects[i]);
}
System.out.println("======================");
//迭代器
Iterator<String> iterator = set.iterator();
while (iterator.hasNext()){
String s = iterator.next();
System.out.println(s);
}
System.out.println("======================");
//增强for
for(String s :set){
System.out.println(s);
}
1.3Set集合的唯一性原理
查看HashSet对象的add方法,发现是调用map.put方法,再往上查看,找到putVal方法
//K key:要添加的元素
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
boolean evict) {
Node<K,V>[] tab; Node<K,V> p; int n, i;
if ((tab = table) == null || (n = tab.length) == 0)//table是前文定义的不被序列化的节点,如果为空或者长度为0,调用resize()方法重新分配表
n = (tab = resize()).length;
if ((p = tab[i = (n - 1) & hash]) == null)
tab[i] = newNode(hash, key, value, null);
else {
Node<K,V> e; K k;
//会首先比较Hash值(每个元素都会调用hashcode()产生一个哈希值)
//如果新添加的元素与集合中已有的元素的哈希值都不同,那新的元素存入集合
//如果新添加的元素与集合中已有的某个元素哈希值相同,此时还需要调用equals方法比较地址
//如果方法返回true,说明新添加的元素与集合中的某个元素属性相同,则新元素不加入到集合
//如果返回false,说明新添加的元素与集合中所有的元素属性都不同,新元素加入到集合中
if (p.hash == hash &&
((k = p.key) == key || (key != null && key.equals(k))))
e = p;
else if (p instanceof TreeNode)
e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
else {
for (int binCount = 0; ; ++binCount) {
if ((e = p.next) == null) {
p.next = newNode(hash, key, value, null);
if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
treeifyBin(tab, hash);
break;
}
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
break;//相同,则退出循环
p = e;
}
}
if (e != null) {
V oldValue = e.value;
if (!onlyIfAbsent || oldValue == null)
e.value = value;
afterNodeAccess(e);
return oldValue;
}
}
++modCount;
if (++size > threshold)
resize();
afterNodeInsertion(evict);
return null;
}
1.4HashSet存储自定义对象
我们自定义对象,并将它存储到set集合中,会发现重复的对象可以写进同一个集合,那如何解决这个问题呢?前面提到过,set集合具有成员唯一性,存入元素不能重复,java中检查元素是否重复是通过检查哈希值与地址值,所以,我们可以通过重写equals()方法和hashcode()方法来解决这个问题:
主要是通过重写equals(Object obj)方法和hashCode方法
public class Student {
private String name;
private Integer age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Student() {
}
public Student(String name, Integer age) {
this.name = name;
this.age = age;
}
@Override
public boolean equals(Object o) {
//优化:提高效率
if(this == o){
return true;
}
//提高健壮性
if(this.getClass() != o.getClass()){
return false;
}
Student student = (Student)o;//向下转型,可可以获取子类的对象成员
//比较年龄是否相等,如果不等则返回false
if (!this.age.equals(student.age)){
return false;
}
//比较姓名是否相等,如果不等则返回false
if (!this.name.equals(student.name)){
return false;
}
//默认返回true,说明两个学生是相等的
return true;
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
}
可以使用集成开发工具如Eclipse,Intellij IDEA中提供的equals()与hashcode()重写方法
1.5 Collections工具类
Collection和Collections有什么区别?
Collection是集合体系的最顶层,包含了集合体系的共性
Collections是一个工具类,方法都是用于操作Collection
Collections中常用方法
static void swap(List list, int i, int j) :将指定列表中的两个索引进行位置互换
static void sort(List<T> list) :按照列表中元素的自然顺序进行排序
static void shuffle(List list):随机置换
static void reverse(List list) :反转
static void fill(List list, Object obj) :使用指定的对象填充指定列表的所有元素
static void copy(List dest, List src) :是把源列表中的数据覆盖到目标列表
注意:目标列表的长度至少等于源列表的长度
static int binarySearch(List list, Object key) 使用二分查找法查找指定元素在指定列表的索引位置
注意
Collections的方法中,返回值大多是void,说明这个对象,本身发生了变化,如果返回了新的对象,说明本身可能没有变化,有一个的特殊类StringBuffer的append方法,不会创建新的对象。
- 例如static void shuffle(List list)随机置换方法,返回值void,说明随机置换了list对象,如果返回值是新的对象如List list1对象,说明传递过来的list对象没有发生变化,置换的是返回值list1对象
2.HashMap集合
2.1Map和Collection的区别
Map:是一个双列集合,元素是成对存在的,通常用于处理有对应关系的数据,键是不可以重复的,但是值是可以重复的,每个键只能对应一个值
Collection:是一个单列集合,元素是孤立存在的,向集合中存储元素采用一个个元素的方式存储
2.2Map的常用功能
映射功能
- V put(K key,V value):将key映射到value功能,如果key存在,则覆盖value,返回原value值,如果key不存在,则返回null
获取功能
- V get(Object Key):返回指定key所对应的value
- Set keySet():获取所有的key
- Collection values:获取所有的value
- int size():返回对应关系的个数
判断功能
- boolean containsKey(Object Key):判断指定的key是否存在
- boolean containsValue(Object Value):判断指定的value是否存在
- boolean isEmpty():判断是否有对应关系
删除功能
- void clear():清除所有的对应关系
- V remove(Object Key):根据指定的key删除对应关系,并返回key所对应的值。如果没有删除成功,则返回null
遍历功能
- Set<Map.Entry<K,V>> entrySet():Map的第二种遍历方法,通过面向对象
2.3案例
public class MapDemo {
public static void main(String[] args) {
Map<String ,String > map = new HashMap<>();
//添加功能 V put(K key,V value) :将key映射到value功能,如果key存在,则覆盖value,返回原value值,如果key不存在,则返回null
map.put("001","小一");
map.put("002","小二");
map.put("003","小三");//返回null
map.put("001","小四");//key值存在,会返回原value值“小一”,并覆盖value,现在key "001"对应的是"小四"。判断是否重复,参加上方set集合的add方法
//判断功能:boolean containsKey(Object Key):判断指定的key是否存在
System.out.println(map.containsKey("001"));//返回true
//判断功能:boolean containsValue(Object Value):判断指定的value是否存在
System.out.println(map.containsValue("小一"));//返回false,小一已经被小四取代了
//判断功能:boolean isEmpty():判断是否有对应关系
System.out.println(map.isEmpty());
//删除功能:void clear():清除所有的对应关系
map.clear();
//删除功能: V remove(Object Key):根据指定的key删除对应关系,并返回key所对应的值。如果没有删除成功,则返回null
map.put("001","小一");
map.put("002","小二");
map.put("003","小三");
System.out.println(map.remove("001"));
//获取功能:int size():返回对应关系的个数
System.out.println(map.size());
//获取功能: V get(Object Key):返回指定key所对应的value
System.out.println(map.get("003"));
//获取功能:Set<K> keySet():获取所有的key
Set<String> set = map.keySet();//返回值是Set类型:是因为map集合中key是唯一不可重复的,而set类型具有元素的唯一性
for (String key :set){
System.out.println(key);
}
//获取功能:Collection<V> values:获取所有的value
Collection<String> collection = map.values();//返回值是Collection类型:是因为map集合中value值是允许重复的,如果返回set,重复的值就不存在了,而collection是允许重复的。注意:不是list类型
for(String value:collection){
System.out.println(value);
}
//Map的第一种遍历方式:获取所有的key,遍历key,通过key找到map中的value
Set<String> keys = map.keySet();
for (String key :keys){
System.out.println(map.get(key));
}
//遍历功能:Set<Map.Entry<K,V>> entrySet():Map的第二种遍历方法,通过面向对象
Set<Map.Entry<String ,String>> entrys=map.entrySet();
for (Map.Entry<String ,String> entry:entrys){
String key = entry.getKey();
String value = entry.getValue();
System.out.println("key:"+key+"value:"+value);
}
/**原理
* class Entry<K,V>{
* K key;
* V value;
* public Entry(K key,V value){
* this.key = key;
* this.value = value;
* }
*
* public K getKey(){
* return key;
* }
*
* public V getValue(){
* return value;
* }
* }
*/
}
}
今日小结
- 今天主要重新回顾了Set集合与Map集合,真的,每回顾一次,就发现自己了解的并不多。以前顶多是可以熟练运用,今天算是可以勉强理解其中的一点原理。当然还不够,底层的添加方法还使用了二叉树的相关知识,这是我的盲点,恩,记下来,这也是需要攻克的。今天就到这里吧。