【JavaSE基础】08-集合框架(三)
文章目录
- Set 接口
- 0:接口说明
- 1:功能概述
- 2、实现子类
- HashSet
- LinkedHashSet
- TreeSet
- Comparable 自然排序接口
- Comparator 比较器接口
- Map 接口
- 0:接口说明
- 1:功能概述
- 2:实现子类
- HashMap
- LinkedHashMap
- TreeMap
- 综合案例
- 面试题
- 集合工具类 Collections
- 0:类的描述
- 1:功能概述
- 集合框架
- 通用方法
- 性能测试
- List性能比较
- Set性能比较
- Map性能比较
Set 接口
public interface Set<E> extends Collection<E>
0:接口说明
Set 接口是对数学中的集合的抽象,满足集合的一般性质:
- 无序性(进出顺序)
- 唯一性(不包含重复元素)
- 至多一个null值元素(可以没有)
1:功能概述
Set 接口完全继承,并根据集合的特点重写了 Collection的 15个方法。没有任何特有方法。
- 添加功能 2 add、addAll
- 删除功能 4 clear、remove、removeAll、retainAll
- 获取功能 3 size、Iterator、hashCode
- 判断功能 4 isEmpty、equals、contains、containsAll
- 转换功能 2 toArray、toArray
Set
VS
List 异同点
不同点:
- Set:无序的集合,不可重复,无索引,无任何特有方法
- List:有序的集合,可重复,有索引,10个特有方法 【针对索引的 添加功能:add、addAll;针对索引的 删除功能:remove;读写器:get、set;特有遍历:listIterator、listIterator(index);获取功能:indexOf、lastIndexOf(高开销的线性搜索);获取局部视图功能:subList (操作的时候,直接映射到原来的List上面)】
相同点:
- 两者同时继承了 Collection 的15个基本操作方法,以及作为集合的特性(可变的数组:数据类型可变、元素个数可变)
- Set 没有 关于索引的操作,以及读写器,源于Set的无序性
2、实现子类
HashSet
public class HashSet<E> extends AbstractSet<E> implements Set<E>, Cloneable, Serializable
0:类的描述:
此类实现 Set 接口,由哈希表(实际上是一个 HashMap 实例【参见 构造器的底层源码】) 支持的。不保证集合的 迭代顺序,特别是不保证此顺序恒久不变,此类允许 null 元素。
此类为基本操作提供了稳定的性能,这些基本操作是 add、remove、contains 和 size。 假设 哈希函数将这些元素正确分布在桶中。对此 set 进行迭代所需时间与 HashSet 实例的大小(元素的数量)和 底层 HashMap 实例(桶的数量)的“容量”的和成正比。因此,如果迭代器的性能很重要,则不要将初始容量设置的太高。(或将加载因子设置的太低)
此类 单线程高效,需要同步进行安全访问的时候,粗腰创建 同步的集合Collections.synchroniizedSet(new HashSet(...))
请注意,并发修改异常 ConcurrentModificationException
:创建迭代器之后,使用集合的方法进行集合元素的修改,Iterator抛出的异常,是快速失败。
1:功能方法
根据哈希表的结构,来实际分析 基本操作的 实现原理:
add:实现的过程:(1)获取需添加的元素的
hashCode()
,根据元素的 哈希值(和哈希函数) 找到 链表在数组中位置;(2)遍历链表,使用equals()
进行判断,如果已经存在 直接返回 false;否则添加在链表最后,并返回true。remove:实现过程:(1)获取需删除的元素的
hashCode()
,根据元素的 哈希值(和哈希函数) 找到 链表在数组中位置;(2)遍历链表,使用equals()
进行判断,如果存在 直接删除,并返回true;否则直接返回 false。contains:实现过程:(1)获取需判断的元素的
hashCode()
,根据元素的 哈希值(和哈希函数) 找到 链表在数组中位置;(2)遍历链表,使用equals()
进行判断,如果存在,则返回 true,否则返回 falsesize:实现过程:直接遍历数组中每个链表的,返回 所有链表的元素个数之和。
package com.rupeng.set;import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;public class Demo2
{public static void main(String[] args){Set set = new HashSet();set.add("com");set.add("Rupeng");set.add("www");Iterator it = set.iterator();while (it.hasNext()){String str = (String) it.next();System.out.println(str);}/** 虽然 进出的顺序相同,但不能说明 Set 是有序的。 *//** 暂且将有序定义为:不论如何添加元素,在写代码的那一刻,你就知道取出时的顺序了 *//** 比如:数组列表、队列、栈等有序集合 */}
}
注意一个问题:
虽然 Set 是无序的,但也有自身的 存储结构。所以即使是说 向 Set 中添加元素的顺序和遍历取出的顺序相同,并不能说明 Set 的有序性。
说完了 有序的问题,再来看看 Set 集合的唯一性,是如何保证的?实际上,Set 基本操作的实现过程已经说明了,Set 元素唯一性的原因:
- 先看
hashCode()
值是否相同,不相同 直接添加到集合中(作为新链表的首元素);相同 则继续看equals()
比较的结果,返回 true ,元素存在 不添加;返回 false ,原始不存在,添加到集合中(作为原有链表的尾元素)
源码分析:
// HashMap 类中 实现添加最核心的语句
if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k))))
{break;
}
默认情况下,hashCode()
和 equals()
都是继承自Object超类的,进行比较的是地址值,但是有些情况下,比较地址值的意义不大,相反,使用类的成员变量的比较更有意义。比如:两个学生是否相等,如果是用地址值比较的话,因为在堆内存中不可能公用一块地址,即使是同一个人实例化两次,也会得到 为 false 的判断结果,这个时候,就需要重写 这两个方法 了。
案例1:创建字符串的 HashSet 集合
package com.rupeng.set;import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;public class Demo2
{public static void main(String[] args){Set set = new HashSet();set.add("com");set.add("Rupeng");set.add("www");set.add("Rupeng");Iterator it = set.iterator();while (it.hasNext()){String str = (String) it.next();System.out.println(str);}}
}
String 类 重写了来自 Object 的 hashCode()
和 equals()
,对于相等的比较,是按位比较 字符串中的每个字符是否相等。故此,可以保证元素的唯一性。
案例2:创建自定义学生对象的 HashSet 集合
package com.rupeng.set;import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;public class Demo3
{public static void main(String[] args){Student stu1 = new Student("Cathy", 18);Student stu2 = new Student("Cathy", 18);Student stu3 = new Student("Ian", 17);Student stu4 = new Student("Ian", 17);Set<Student> set = new HashSet<Student>();set.add(stu1);set.add(stu2);set.add(stu3);set.add(stu4);for (Iterator<Student> it = set.iterator(); it.hasNext();){Student st = it.next();System.out.println(st);}}
}
从代码的执行结果,可能会觉得错了。实际上 计算器 又被冤枉了,它只是按照 引用对象的地址值进行比较,确定两个值是不是相等的,而我们想要的是 通过对象的成员变量的比较来确定两个 对像是不是相等,这个时候就需要 在自定义类 Student 中重写 那两个关键的方法(hashCodse()
和 equals()
)了。【为了更加方便地输出 学生信息,可以重写 toString()
方法】
// 只是简单的重写,程序的健壮性什么的没有考虑
// 更完善的代码,可以直接使用 快捷键生成 这两个方法
// 快捷键:ALT + SHIFT + S + 键盘键入 h或H
@Override
public int hashCode()
{return name.hashCode() + age * 2015;
}@Override
public boolean equals(Object obj)
{Student other = (Student) obj;if (other == this){return true;}if (other.getName() == name){if (other.getAge() == age){return true;}}return false;
}
综上,HashSet 如何保证 元素的唯一性
- a、底层数据结构是 哈希表【元素是链表的 数组】
- b、哈希表依赖于哈希值存储
- c、添加功能底层实现依赖两个方法 (
hashCodse()
和equals()
)
LinkedHashSet
public class LinkedHashSet<E> extends HashSet<E> implements Set<E>, Cloneable, Serializable
a、可预知迭代顺序的 Set接口,底层是哈希表和链表的实现
b、元素有序且唯一,允许 null 元素
【哈希表保证元素的唯一性,链表保证元素的有序性】,增删效率高
c、按照链表定义的迭代顺序与其插入顺序相同
d、单线程高效,安全需要时,使用同步Set集合方式定义 Collections.synchronizedSet(new LinkedHashSet(...));
,同样存在快速失败的 并发修改异常 ConcurrentModificationException
。
TreeSet
public class TreeSet<E> extends AbstractSet<E> implements NavigableSet<E>, Cloneable, Serializable
public interface NavigableSet<E> extends SortedSet<E>
0:类的描述
根据实际的继承关系,可以知道 NavigableSet 接口实现了一个排序的接口。
TreeSet 是基于 TreeMap 的 NavigableSet 实现,实际上是 TreeMap 的一个实例。使用元素的自然顺序(Comparable)对元素进行排序,或者根据创建 set 时提供的 Comparator 进行排序,具体取决于使用的构造方法。
此实现为基本操作(add、remove 和 contains)提供受保证的 log(n) 时间开销
。 (时间复杂度)
TreeSet 具有 唯一性和排序性。不允许 null 元素
增删效率高
因为二叉树对于位置的定位很快,所以无论是添加 删除 效率都很高。
添加时:只需要定位添加的位置
删除时:只需要定位待删除元素的位置
1:数据结构
TreeSet 底层数据结构是 红黑树(Red-Blank Tree),也就是自平衡的二叉查找树(元素的快速查找
)
二叉查找树:每个节点有且只有一个父节点,最多存在两个子节点,并且该节点的值大于等于左子树中的所有节点,小于等于右子树的所有节点。
存储方式:
- 第一个元素作为 Root 元素
- 之后的元素和Root元素 比较
- 大于 Root – 在右子树中进行存储
- 小于 Root – 在左子树中进行存储
- 等于 Root – 不进行存储
取出方式:
深层 -自上而下 三种主要的遍历方式
- a、先序遍历 Root - Left - Right
- b、中序遍历 Left - Root - Right
- c、后序遍历 Left - Right - Root
注意:不论是存储还是取出的时候,这种定义都是 递归 的
简单元素的存取:
说明: 从上面的存储过程,证明 TreeSet 实际上在存元素时,就已经给定了一个顺序了,之后 取出的元素 是按照 从小到大的,再结合 二叉查找树的遍历结结果 可以知道,实际上 TreeSet 迭代实现是 中序遍历 。
2:功能方法
自然排序 构造器:public TreeSet()
比较器排序 构造器:public TreeSet(Comparator<? extends E> c)
其余功能方法和Set一致,不再赘述。
案例1:创建字符串的 TreeSet 集合
package com.rupeng.set;import java.util.Iterator;
import java.util.Set;
import java.util.TreeSet;public class TreeSetDemo1
{public static void main(String[] args){Set<String> set = new TreeSet<String>();set.add("Javase");set.add("Rupeng");set.add("JoianSUN");set.add("Shanhai");set.add("20150705");for (Iterator<String> it = set.iterator(); it.hasNext();){String str = it.next();System.out.println(str);}}
}
案例2:创建自定义对象的 TreeSet 集合
package com.rupeng.set;import java.util.Iterator;
import java.util.Set;
import java.util.TreeSet;public class TreeSetDemo2
{public static void main(String[] args){Set<Student> set = new TreeSet<Student>();set.add(new Student("Joian", 18));set.add(new Student("Du", 27));set.add(new Student("Yzk", 10));for (Iterator<Student> it = set.iterator(); it.hasNext();){Student stu = it.next();System.out.println(stu);}}
}
无法将 Student 转换为 Comparable :Student 不是接口 Comparable 的实现类,所以无法装换。
在构造 TreeSet 对象的时候,使用了默认的构造器,集合中元素的排序方式是自然排序,也就是说 添加到集合的元素必须是 Comparable 接口的实现类实例。否则报错。简言之:需要的 Comparable 接口的实现类实例,实际是 未实现接口的 Student 。之所以 String 类可以正常添加,是因为 String 类实现了 Comparable 接口。
如何解决呢?
- 让自定义对象实现 Comparable 自然排序 接口;
- 使用比较器 Comparator的构造,让集合有序
为了篇幅的整齐,直接在此处给出具体的解决方案。进行具体的问题解决之前,先去看一下 这两个 接口的相关内容吧,就在这一节的后面。
解决方案1:元素 实现 自然排序接口
// 仅仅给出了 Comparable 接口的方法实现
public class Student implements Comparable<Student>
{/** 实现的是 先按照姓名升序,姓名相同,按照年龄升序 */@Overridepublic int compareTo(Student o){int result = getName().compareTo(o.getName());if (result == 0){return getAge() - o.getAge();} else{return result;}}
}
解决方案2:TreeSet 实现 比较器接口的构造
// 使用比较器 构造 TreeSet 对象,并对代码进行了重构
/** 实现的是 先按照姓名升序,姓名相同,按照年龄升序 */
Set<Student> set = new TreeSet<Student>(new Comparator<Student>()
{@Overridepublic int compare(Student o1, Student o2){int result = o1.getName().compareTo(o2.getName());if (result == 0){result = o1.getAge() - o2.getAge();}return result;}
});
实现的是 先按照姓名升序,姓名相同,按照年龄升序
,实际完成需求时,需要自行取分析主要条件和次要条件,譬如:给定的需求会是 请按照学生姓名对集合中的元素进行升序排序,那么 主要条件是 姓名,次要条件是 年龄(如果姓名相同的话,如何按照年龄排序,可升序 可降序)
案例:根据学生的姓名长度进行排序
package com.rupeng.set;import java.util.Comparator;
import java.util.Iterator;
import java.util.Set;
import java.util.TreeSet;/*** 需求:根据学生姓名长度进行升序排序* * 分析:* (1)主要条件:学生姓名长度* (2)次要条件:学生姓名、学生年龄* * 编码实现:* 因为实际给定了一个 比较,使用比较器 构造 TreeSet,* 相对 使Student 实现自然排序,更有意义,自然排序 应该是只和对象成员变量本身有关,* 才更有意义,而且一般不要更改已经写好的 类*/
public class TreeSetDemo3
{public static void main(String[] args){Set<Student> set = new TreeSet<Student>(new Comparator<Student>(){@Overridepublic int compare(Student o1, Student o2){int result = o1.getName().length() - o2.getName().length();if (result == 0){result = o1.getName().compareTo(o2.getName());if (result == 0){result = o1.getAge() - o2.getAge();}}return result;}});set.add(new Student("Joian", 18));set.add(new Student("Cathy", 18));set.add(new Student("Du", 27));set.add(new Student("Du", 27));set.add(new Student("Yzk", 10));set.add(new Student("Yzk", 19));Iterator<Student> it = set.iterator();while (it.hasNext()){Student stu = it.next();System.out.println(stu);}}
}
TreeSet 的排序方式 取决于使用的构造方法:public TreeSet()
自然排序,public TreeSet(Comparator<? extends E> c)
比较器排序
public TreeSet(Comparator<? extends E> c)
/*** 接口 作为参数传递,实际需要的是 接口的实现类对象:* 主要三种方式 给定 实现类对象* (1)匿名内部类(最常用)* (2)外部类* (3)借口实现*/
TreeSet 唯一性和元素排序的原理
- A :唯一性:底层数据结构红黑树支持,具体实现是 比较的返回值是否为 0 来决定
- B :排序:
- a 、自然排序(元素具有比较性)让元素所属类实现 Comparable 自然排序接口
- b 、比较器排序(TreeSet具有比较性) 给 TreeSet 构造方法提供一个 Comparator 比较器接口实现类对
理解
- 元素具有比较性:学生按照
自身身高
在教室中中坐座位- 集合具有比较性:学生按照教室中
给定的编号
坐座位
综合案例1:使用HashSet 重新实现:获取 10个 1~20 范围内的整数,且不可重复
package com.rupeng.set;import java.util.HashSet;
import java.util.Random;
import java.util.Set;public class HashSetDemo
{public static void main(String[] args){Random random = new Random();Set set = new HashSet();while (set.size() < 10){int num = random.nextInt(20) + 1;set.add(num);}System.out.println(set);}
}
综合案例2:键盘录入五个学生的成绩信息,按照总分降序排序
package com.rupeng.set;import java.util.Comparator;
import java.util.Scanner;
import java.util.Set;
import java.util.TreeSet;/*** 需求:键盘录入五个学生的成绩信息,按照总分降序排序 * 格式 为: 姓名 语文成绩 数学成绩 英语成绩。譬如:Joian 90 89 100*/
public class TreeSetDemo
{public static void main(String[] args){Scanner sc = new Scanner(System.in);String[] strs = new String[5];for (int i = 0; i < strs.length; i++){System.out.println("Please enter the No."+(i + 1)+" student's record:");strs[i] = sc.nextLine();}sc.close();Set<Student> set = new TreeSet<Student>(new Comparator<Student>(){public int compare(Student o1, Student o2){/* int result = o2.getTotal() - o1.getTotal();if (result == 0){result = o1.getName().compareTo(o2.getName());if (result == 0){result = o1.getChinese() - o2.getChinese();if (result == 0){result = o1.getMath() - o2.getMath();if (result == 0){result = o1.getEnglish() - o2.getEnglish();}}}}return result;*/int num1 = o2.getTotal() - o1.getTotal();int num2 = (num1 == 0) ? (o1.getName().compareTo(o2.getName())): num1;int num3 = (num2 == 0) ? (o1.getChinese() - o2.getChinese()): num2;int num4 = (num3 == 0) ? (o1.getMath() - o2.getMath()) : num3;int num5 = (num4 == 0) ? (o1.getEnglish() - o2.getEnglish()): num4;return num5;};});for (String str : strs){String[] info = str.split(" ");Student stu = new Student(info[0], Integer.parseInt(info[1]),Integer.parseInt(info[2]), Integer.parseInt(info[3]));set.add(stu);}System.out.println("----------------------------");for (Student st : set){System.out.println(st.printScore());}}
}
Comparable 自然排序接口
底层源码:
public interface Comparable<T>
{public int compareTo(T o);// 实际修饰符 应该是 public abstract
}
接口强行对实现它的每一个类进行整体排序,称为类的 自然排序。类的方法 compareTo
被称为 自然排序方法。
实现此接口的对象集合和数组,可以通过对应工具类中的 sort 方法(
Collections.sort()
和Arrays.sort()
)进行整体排序。实现此接口的对象可以作为 有序映射(SortedMap)的键和有序集合(SortedSet)的元素,无需指定比较器(Comparator) (
TreeMap 和 TreeSet 就是有序映射、集合
)
对于集合两个对象 e1 和 e2 ,当且仅当 e1.equals(e2)
和 e1.compareTo(e2)==0
返回相同的 boolean 值时,类的自然排序才叫做与 equals 一致。 现阶段 我们需要这种一致,如果不一致的话,会出现很奇怪的想象,所以注意 与equals一致
。实际上,所有实现 Comparable 接口的 Java 核心类都具有与 equals 一致的自然排序。 但是 java.util.BigDecimal
是个特例,它的自然排序 将值相同、精度不同的对象视为相等。
注意: null 不是任何类型的实例,即使
e.euaals(null)
返回false,e.compareTo(null)
也会抛出异常NullPointerException
。 这个就是 为什么 TreeSet 元素 和 TreeMap 的键 不允许 null 元素的原因。
功能方法
public abstract int compareTo(T o);
比较当前对象与指定对象的顺序。如果当前对象小于、等于或大于指定对象,则分别返回负整数、零或正整数。
实现整体排序,实际的底层 是 常见的排序算法。
注意:
ClassCastException
异常,如果 o 无法转换为指定类的对象。
Comparator 比较器接口
底层源码:Java 1.8 之前
public interface Comparator<T>
{// Java 1.8 以前 全部的方法int compare(T o1, T o2);boolean equals(Object obj);// 实际修饰符:public abstract
}
强行对实现接口的 对象集合进行整体排序的比较器。
可以将 Comparator 传递给 sort 方法 (
Collections.sort()
和Arrays.sort()
) 从而实现排序顺序的精确控制。可以将使用 Comparator 来控制某些数据结构的顺序 (有序映射 TreeMap 和 有序集合 TreeSet)
可以为没有实现自然排序的对象 的集合提供排序
对于Comparator c 的两个元素 e1 和 e2 ,当且仅当 e1.equals(e2)
和 c.compare(e1, e2)==0
返回相同的 boolean 值时,Comparator c 提供的排序才叫做与 equals 一致。
功能方法
int compare(T o1, T o2);
比较用来排序的两个参数。根据第一个参数小于、等于或大于第二个参数分别返回负整数、零或正整数。
注意:
ClassCastException
异常,如果 o1、o2 无法转换为指定类的对象。
boolean equals(Object obj);
指示某个其他对象是否“等于”此 Comparator。仅当 指定的对象也是一个 Comparator,并且强行实施与此 Comparator 相同的排序时,此方法才返回 true。
Map 接口
0:接口说明
public interface Map<K,V>
java.util 包下。
Map 接口是 键映射到值的对象。 键具有唯一性,值可重复 。 Map 实际对应的是 数学中函数。键为自变量,值为因变量。 Map 中的每一个键值对,实际就是 函数中每一个自变量与所得因变量的对应关系,这种对应关系在 Map 中的体现是 就是键值对 public static interface Map.Entry<K,V>
,是以内部类(实际是接口)形式定义的 。
public static interface Map.Entry<K,V>
Map 的成员方法
entrySet
返回的就是 Map 的 内部类(接口)Entry 的对象集合 。获得映射项引用的唯一方法就是通过 集合视图的 迭代器 实现(新特性 增强 for实质也是迭代器实现的)
Map.Entry 仅仅在迭代期间有效,更确切来讲,在迭代器返回项之后,修改底层映射,会造成映射行为的不确定性。
注意
:setValue方法例外
。
Map.Entry 接口成员方法:
boolean equals(Object e)
给定对象 为映射项且和当前对象拥有相同的映射关系,返回 true ,更确切的说,满足如下关系的 e1 和 e2 才具有相同的映射关系(e1.getKey() == null ? e2.getKey() == null : e1.getKey().equals(e2.getKey())) && (e1.getValue() == null ? e2.getValue() : e1.getValue().equals(e2.getValue()))
也就是说 当两个 映射项 对的键和值对影响等的是时候,才说 这两个对应关系是 相同对应关系,允许 null 键值,这可以确保 equals 方法在不同的 Map.Entry 接口实现间可正确地工作。(定义中之所以使用 equals 方法 而不是 == ,是因为可能存在着需要 自定义的相等关系,而不只是 地址相等,可能会是 对象的成员变量对应相等,即视为 对象相等这样的定义,这很常见)int hashCode()
返回此映射项的哈希码值。 映射项 e 的哈希码值的定义如下:(e.getKey() == null ? 0 : e.getKey().hashCode())^(e.getValue() ? 0 :e.getValue().hashCode())
这个确保e1.equals(e2)
因为着 对于任意的两个项 e1 和 e2 而言e1.hashCode() == e2.hashCode()
,这也正是Object.hashCode
常规协定所要求的。K getKey()
获取当前映射项的键V getValue()
获取当前映射项的值V setValue(V value)
设置 当前映射项的值 (注意各种异常),返回 旧的值
Map 接口提供了三个视图:
- 键的集合:键具有唯一性
public Set<K> keySet()
- 值的集合:值可重复
public Collection<V> values()
- 映射项的集合:根据键值的点,键值对(映射项)具有唯一性
public Set<Map.Entry<K,V>> entrySet()
三种视图的迭代器,支持移除操作(remove、removeAll、clear),但是不支持添加操作。
映射顺序:迭代器在视图上返回元素的顺序。TreeMap 保证这种顺序,HashMap 不保证这种顺序。(对比 HashSet、TreeSet【底层实现就是 对应的HashMap、TreeMap的键集合】)
通过映射实现类应该有两种构造器:
- 无参构造
public 实现类名()
- 根据已有映射关系复制建立的
public 实现类名(Map<? extends K,? extends V> m)
注意:equals 和 hashCode 的定义必须是明确的。
1:功能概述
先来看看Map与Collection的区别?
- Map 集合元素 是成对出现的 Entry 实例,Entry<K,V> 中 K 是唯一性的,V 是可重复的;Map 集合的数据额结构针对键有效,与值无关
- Collection 集合元素 是单个出现的 Java 任意类(含有自定义类)的实例;Collection 的 子接口中 Set 是唯一的,List 是可重复的;Collection 集合的数据结构针对元素有效
a、添加功能
V put(K key, V value)
修改集合中的映射项,返回的是与 key 关联的旧的值,如果该映射项不存在,则执行添加 并返回 null(注意:如果集合 允许 null 值,返回的 null 包含两种可能性:(1)第一次添加;(2)修改之前的值 是 null )void putAll(Map<? extends K, ? extends V> m)
从指定映射 m 中,将其所有得映射项 复制到 当前的映射中。相当于:从 m 中 遍历每一个映射项,并对当前的 映射 进行 put 方法的调用(修改/添加)
b、删除功能
void clear()
清楚当前映射V remove(Object key)
移除 key 键所在的映射项,如果不存在这样的映射项,则返回 null,如果存在的话,执行删除 并返回 与之对应的 值。 满足的映射项的 键 k 满足以下条件:key == null ? k == null : key.equals(k)
。(注意:如果集合 允许 null 值,返回的 null 包含两种可能性:(1)不能存在对应的映射项;(2)删除的映射项的值 是 null )
c、判断功能
boolean equals(Object o)
给定的 映射 o 和当前映射相等,返回 true,相等的定义是,具有相同的映射关系,也就是o.entrySet().equals(this.entrySet())
返回 true 。注意重写 hashCode 方法,需要满足 Java 的常规协定,hashCode()
返回此映射的哈希码值。映射的哈希码定义为此映射 entrySet() 视图中每个项的哈希码之和。这确保 m1.equals(m2) 对于任意两个映射 m1 和 m2 而言,都意味着m1.hashCode()==m2.hashCode()
,正如 Object.hashCode() 常规协定的要求。boolean isEmpty()
如果 当前的映射不包含任何的键值对(映射项)的话,返回trueboolean containsKey(Object key)
如果此映射包含指定键的映射关系,则返回 true。更确切地讲,当且仅当此映射包含针对满足(key==null ? k==null : key.equals(k))
的键 k 的映射关系时,返回 true。(最多只能有一个这样的映射关系)。boolean containsValue(Object value)
如果此映射将一个或多个键映射到指定值,则返回 true。更确切地讲,当且仅当此映射至少包含一个对满足(value==null ? v==null : value.equals(v))
的值 v 的映射关系时,返回 true。对于大多数 Map 接口的实现而言,此操作需要的时间可能与映射大小呈线性关系。 (Map 的数据结构只是针对 键 有效,所以这个操作是需要 遍历映射的 所有映射项
)
d、获取功能
V get(Object key)
返回指定键所映射的值;如果此映射不包含该键的映射关系,则返回 null。 更确切地讲,如果此映射包含满足(key==null ? k==null : key.equals(k))
的键 k 到值 v 的映射关系,则此方法返回 v;否则返回 null。(最多只能有一个这样的映射关系)。(注意:如果集合 允许null值,返回 null 包含两种含义:(1)不存在该项;(2)该项的值是null)int size()
该映射中键值对(映射项) 的个数。注意 int 值的范围键的集合
:键具有唯一性public Set<K> keySet()
值的集合
:值可重复public Collection<V> values()
映射项的集合
:根据键值的点,键值对(映射项)具有唯一性public Set<Map.Entry<K,V>> entrySet()
获取映射中的项,必须使用 迭代器
- 键集合 + get 方法
- 键值集合 + Entry<K, V> 获取功能
案例:遍历映射实例
- 方式1:键集合 + get 方法
package com.rupeng.map;import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;/** 遍历 映射 */
public class MapDemo1
{public static void main(String[] args){Map<Integer, String> map = new HashMap<Integer, String>();map.put(1, "Joian");map.put(2, "Yzk");map.put(3, "Cathy");map.put(4, "Apple");Set<Integer> set = map.keySet();for (Integer in : set){System.out.println(in + " " + map.get(in));}}
}
- 方式2:键值集合 + Entry<K, V> 获取功能
package com.rupeng.map;import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;/** 遍历 映射 */
public class MapDemo1
{public static void main(String[] args){Map<Integer, String> map = new HashMap<Integer, String>();map.put(1, "Joian");map.put(2, "Yzk");map.put(3, "Cathy");map.put(4, "Apple");Set<Entry<Integer, String>> set = map.entrySet();for (Iterator<Entry<Integer, String>> it = set.iterator(); it.hasNext();){Map.Entry<Integer, String> me = it.next();System.out.println(me.getKey() + " " + me.getValue());}}
}
2:实现子类
HashMap
基于哈希表的Map接口实现。四个特性:
Map 中键唯一,值可重复,映射项唯一
,这个是所有的 Map实现类的**共性
**- Map 的数据结构 只对 键有效,与值无关,第一点的映射项唯一就是依靠键的唯一实现
- HashMap 允许 null 键、null值(但这样的键值对,最多出现一次)
- HashMap 不保证 映射的顺序,特别是不保证其顺序很久不变。
注意
: 如果出现存入的顺序和取出的顺序一样,并不能说明 HashMap的有序性,只是 HashMap 也有其存储的顺序 而已。
使用四个案例 来说明,HashMap的特性
- 案例1:HashMap<String, String>
- 案例2:HashMap<Integer, String>
【JavaSE基础】08-集合框架(三)相关推荐
- Thinking in java基础之集合框架
Thinking in java基础之集合框架 大家都知道我的习惯,先上图说话. 集合简介(容器) 把具有相同性质的一类东西,汇聚成一个整体,就可以称为集合,例如这里有20个苹果,我们把每一个苹果当成 ...
- java把map值放入vector_Thinking in java基础之集合框架
Thinking in java基础之集合框架 大家都知道我的习惯,先上图说话. 集合简介(容器) 把具有相同性质的一类东西,汇聚成一个整体,就可以称为集合,例如这里有20个苹果,我们把每一个苹果当成 ...
- 7.Java基础之集合框架+JDK8新特性
1.集合概述 1.1 为什么学集合 思考:数组有什么缺点? 长度一旦定义,不能改变!定义大了,浪费空间:小了,可能不够 ---->动态的数组 对于增删,需要移动位置 ->有人帮我们做这个事 ...
- java集合框架中抽象有序列表的接口是_JAVA基础接口集合框架
接口 -------------------------------------------------------------------------------- 一.接口(是一种规范) 1.接口 ...
- list集合下标从几开始_Java基础进阶 集合框架详解
今日任务 1.List接口介绍(掌握常用List特有方法) 2.练习 3.ArrayList介绍(必须清楚集合的特征.掌握集合中的方法) 4.LinkedList介绍(必须清楚集合的特征.掌握集合中的 ...
- java list 差集_Java基础之集合框架
Java 集合框架概述 一方面, 面向对象语言对事物的体现都是以对象的形式,为了方便对多个对象的操作,就要对对象进行存储.另一方面,使用Array存储对象方面具有一些弊端,而Java 集合就像一种容器 ...
- java基础复习-集合框架(1)
java集合概述 Java 集合, 也叫作容器,主要是由两大接口派生而来:一个是 Collection接口,主要用于存放单一元素:另一个是 Map 接口,主要用于存放键值对.对于Collection ...
- Java基础_集合框架1
一.集合框架(体系概述) 为什么会出现集合框架(集合类)? 面向对象语言对事物的体现都是以对象的形式,所以为了方便对多个对象的操作,就对对象进行存储,集合就是存储对象最常用的一种方式. 数组和集合框架 ...
- J2EE基础:集合框架—List
文章目录 本节总结知识网思维导图 一.特点 二.遍历 1.fori 2.foreach 3.iter ator(迭代器) 三.LinkedList 四.增长 因子论证 五.集合框架ArrayList中 ...
- Java基础(集合框架——Collection、List、Set、泛型)
为什么出现集合类? 面向对象语言对事物的体现都是以对象的形式,所以为了方便对多 个对象的操作,就对对象进行存储,集合就是存储对象常用的一 种方式. 数组和集合类同是容器,有何不同? 数组虽然也可以存储 ...
最新文章
- filter执行先后问题_Thinkphp5框架变量覆盖导致远程代码执行
- TCExam开源在线考试系统
- Spring Security——login显示[Bad credentials]
- 数据库02_字段类型
- JavaWeb学习总结(一):JavaWeb开发入门
- redhat7基本命令操作
- Mysql 添加用户 授权等操作
- Java泛型的个人理解
- C++ Primer 第三章 标准库类型 笔记
- php获取客户端ip地址
- 电脑主板报警声音的故障现象对照表
- 一颗万能的PD协议芯片,最火的Type-C PD协议芯片“LDR6023“, 它是如何实现各种应用呢?
- java微信订阅号(公众号)开发案例
- 信息学奥赛一本通评测系统P1332
- 柴静《看见》摘抄及小评
- SpringBoot数据库连接池常用配置(mysql+sqlServer)
- xlwings库的基本使用笔记
- MySQL无效的月份_ORACLE 插入时间时显示'无效的月份'的问题
- 二零年的十一月开始 努力做个极简的人
- 远程连接基于VMware虚拟机的linux操作系统
热门文章
- ask fsk psk 数字调制的三种基本形式
- 计算机辅助工业设计应用软件,计算机辅助工业设计(CAID)
- PayPal Data Scientist实习面试经历
- 南达科他州立大学计算机科学,2021年美国南达科他州立大学世界排名第几?入学条件和专业课程解析...
- 某用户为购房办理商业贷款,选择了按月等额本息还款法,计算公式如下,在贷款本金(loan)和月利率(rate)一定的情况下,住房贷款的月还款(money)取决于还款月数(month)
- 《Hadoop权威指南》学习笔记(一)
- 设置不了谷歌浏览器为默认浏览器
- replace、replaceAll、replaceFirst的区别
- 电脑换cpu要重装系统吗
- 计算机员工工资管理系统源代码,C++员工工资管理系统源代码
- Thinking in java基础之集合框架