集合【Map、可变参数、Collections】
第1章 Map接口
1.1 Map接口概述
我们通过查看Map接口描述,发现Map接口下的集合与Collection接口下的集合,它们存储数据的形式不同,如下图。
l Collection中的集合,元素是孤立存在的(理解为单身),向集合中存储元素采用一个个元素的方式存储。
l Map中的集合,元素是成对存在的(理解为夫妻)。每个元素由键与值两部分组成,通过键可以找对所对应的值。
l Collection中的集合称为单列集合,Map中的集合称为双列集合。
l 需要注意的是,Map中的集合不能包含重复的键,值可以重复;每个键只能对应一个值。
l Map中常用的集合为HashMap集合、LinkedHashMap集合。
1.2 Map接口中常用集合概述
通过查看Map接口描述,看到Map有多个子类,这里我们主要讲解常用的HashMap集合、LinkedHashMap集合。
l HashMap<K,V>:存储数据采用的哈希表结构,元素的存取顺序不能保证一致。由于要保证键的唯一、不重复,需要重写键的hashCode()方法、equals()方法。
l LinkedHashMap<K,V>:HashMap下有个子类LinkedHashMap,存储数据采用的哈希表结构+链表结构。通过链表结构可以保证元素的存取顺序一致;通过哈希表结构可以保证的键的唯一、不重复,需要重写键的hashCode()方法、equals()方法。
l 注意:Map接口中的集合都有两个泛型变量<K,V>,在使用时,要为两个泛型变量赋予数据类型。两个泛型变量<K,V>的数据类型可以相同,也可以不同。
1.3 Map接口中的常用方法
l put方法:将指定的键与值对应起来,并添加到集合中
n 方法返回值为键所对应的值
使用put方法时,若指定的键(key)在集合中没有,则没有这个键对应的值,返回null,并把指定的键值添加到集合中;
使用put方法时,若指定的键(key)在集合中存在,则返回值为集合中键对应的值(该值为替换前的值),并把指定键所对应的值,替换成指定的新值。
l get方法:获取指定键(key)所对应的值(value)
l remove方法:根据指定的键(key)删除元素,返回被删除元素的值(value)。
Map接口的方法演示
publicclass MapDemo {
publicstaticvoid main(String[] args) {
//创建Map对象
Map<String, String> map = newHashMap<String,String>();
//给map中添加元素
map.put("星期一","Monday");
map.put("星期日","Sunday");
System.out.println(map);//{星期日=Sunday,星期一=Monday}
//当给Map中添加元素,会返回key对应的原来的value值,若key没有对应的值,返回null
System.out.println(map.put("星期一","Mon")); // Monday
System.out.println(map);//{星期日=Sunday,星期一=Mon}
//根据指定的key获取对应的value
String en = map.get("星期日");
System.out.println(en);//Sunday
//根据key删除元素,会返回key对应的value值
String value = map.remove("星期日");
System.out.println(value);//Sunday
System.out.println(map);//{星期一=Mon}
}
}
1.4 Map集合遍历键找值方式
键找值方式:即通过元素中的键,获取键所对应的值
操作步骤与图解:
1.获取Map集合中所有的键,由于键是唯一的,所以返回一个Set集合存储所有的键
2.遍历键的Set集合,得到每一个键
3.根据键,获取键所对应的值
代码演示:
publicclass MapDemo {
publicstaticvoid main(String[] args) {
//创建Map对象
Map<String, String> map = newHashMap<String,String>();
//给map中添加元素
map.put("邓超","孙俪");
map.put("李晨","范冰冰");
map.put("刘德华","柳岩");
//获取Map中的所有key
Set<String> keySet = map.keySet();
//遍历存放所有key的Set集合
Iterator<String> it =keySet.iterator();
while(it.hasNext()){
//得到每一个key
String key = it.next();
//通过key获取对应的value
String value = map.get(key);
System.out.println(key+"="+value);
}
}
}
1.5 Entry键值对对象
在Map类设计时,提供了一个嵌套接口:Entry。Entry将键值对的对应关系封装成了对象。即键值对对象,这样我们在遍历Map集合时,就可以从每一个键值对(Entry)对象中获取对应的键与对应的值。
l Entry是Map接口中提供的一个静态内部嵌套接口。
l getKey()方法:获取Entry对象中的键
l getValue()方法:获取Entry对象中的值
l entrySet()方法:用于返回Map集合中所有的键值对(Entry)对象,以Set集合形式返回。
1.6 Map集合遍历键值对方式
键值对方式:即通过集合中每个键值对(Entry)对象,获取键值对(Entry)对象中的键与值。
操作步骤与图解:
1.获取Map集合中,所有的键值对(Entry)对象,以Set集合形式返回。
2.遍历包含键值对(Entry)对象的Set集合,得到每一个键值对(Entry)对象
3.通过键值对(Entry)对象,获取Entry对象中的键与值。
publicclass MapDemo {
publicstaticvoid main(String[] args) {
//创建Map对象
Map<String, String> map = newHashMap<String,String>();
//给map中添加元素
map.put("邓超","孙俪");
map.put("李晨","范冰冰");
map.put("刘德华","柳岩");
//获取Map中的所有key与value的对应关系
Set<Map.Entry<String,String>> entrySet =map.entrySet();
//遍历Set集合
Iterator<Map.Entry<String,String>> it =entrySet.iterator();
while(it.hasNext()){
//得到每一对对应关系
Map.Entry<String,String> entry = it.next();
//通过每一对对应关系获取对应的key
String key = entry.getKey();
//通过每一对对应关系获取对应的value
String value = entry.getValue();
System.out.println(key+"="+value);
}
}
}
注意:Map集合不能直接使用迭代器或者foreach进行遍历。但是转成Set之后就可以使用了。
1.7 HashMap存储自定义类型键值
练习:每位学生(姓名,年龄)都有自己的家庭住址。那么,既然有对应关系,则将学生对象和家庭住址存储到map集合中。学生作为键, 家庭住址作为值。
注意,学生姓名相同并且年龄相同视为同一名学生。
l 学生类
publicclass Student {
private Stringname;
privateintage;
//编写构造方法,文档中已省略
//编写get,set方法,文档中已省略
//编写toString方法,文档中已省略
}
l 测试类
public class HashMapTest {
public staticvoid main(String[] args) {
//1,创建hashmap集合对象。
Map<Student,String>map = newHashMap<Student,String>();
//2,添加元素。
map.put(newStudent("lisi",28),"上海");
map.put(newStudent("wangwu",22),"北京");
map.put(newStudent("zhaoliu",24),"成都");
map.put(newStudent("zhouqi",25),"广州");
map.put(newStudent("wangwu",22),"南京");
//3,取出元素。键找值方式
Set<Student>keySet = map.keySet();
for(Student key: keySet){
Stringvalue = map.get(key);
System.out.println(key.toString()+"....."+value);
}
//取出元素。键值对方式
Set<Map.Entry<Student,String>> entrySet =map.entrySet();
for (Map.Entry<Student, String>entry : entrySet){
Studentkey = entry.getKey();
Stringvalue = entry.getValue();
System.out.println(key.toString()+"....."+value);
}
}
}
l 当给HashMap中存放自定义对象时,如果自定义对象作为key存在,这时要保证对象唯一,必须复写对象的hashCode和equals方法(如果忘记,请回顾HashSet存放自定义对象)。
l 如果要保证map中存放的key和取出的顺序一致,可以使用LinkedHashMap集合来存放。
1.8 LinkedHashMap
我们知道HashMap保证成对元素唯一,并且查询速度很快,可是成对元素存放进去是没有顺序的,那么我们要保证有序,还要速度快怎么办呢?
在HashMap下面有一个子类LinkedHashMap,它是链表和哈希表组合的一个数据存储结构。
publicclassLinkedHashMapDmeo {
publicstaticvoid main(String[] args) {
LinkedHashMap<String, String> map =new LinkedHashMap<String,String>();
map.put("邓超","孙俪");
map.put("李晨","范冰冰");
map.put("刘德华","柳岩");
Set<Entry<String,String>> entrySet = map.entrySet();
for (Entry<String, String> entry : entrySet) {
System.out.println(entry.getKey()+" "+entry.getValue());
}
}
}
结果:
邓超 孙俪
李晨 范冰冰
刘德华 柳岩
1.9 可变参数
在JDK1.5之后,如果我们定义一个方法需要接受多个参数,并且多个参数类型一致,我们可以对其简化成如下格式:
修饰符返回值类型方法名(参数类型...形参名){ }
其实这个书写完全等价与
修饰符返回值类型方法名(参数类型[]形参名){ }
只是后面这种定义,在调用时必须传递数组,而前者可以直接传递数据即可。
jdk1.5以后。出现了简化操作。...用在参数上,称之为可变参数。
同样是代表数组,但是在调用这个带有可变参数的方法时,不用创建数组(这就是简单之处),直接将数组中的元素作为实际参数进行传递,其实编译成的class文件,将这些元素先封装到一个数组中,在进行传递。这些动作都在编译.class文件时,自动完成了。
代码演示:
public class ParamDemo {
publicstaticvoidmain(String[] args) {
int[]arr = {21,89,32};
intsum = add(arr);
System.out.println(sum);
sum =add(21,89,32);//可变参数调用形式
System.out.println(sum);
}
//JDK1.5之后写法
publicstaticintadd(int...arr){
intsum = 0;
for(inti = 0; i < arr.length; i++) {
sum+= arr[i];
}
return sum;
}
//原始写法
/*
public static int add(int[] arr) {
int sum = 0;
for (int i = 0; i < arr.length; i++) {
sum += arr[i];
}
return sum;
}
*/
}
l 上述add方法在同一个类中,只能存在一个。因为会发生调用的不确定性
注意:如果在方法书写时,这个方法拥有多参数,参数中包含可变参数,可变参数一定要写在参数列表的末尾位置。
1.10 Collections集合工具类
Collections是集合工具类,用来对集合进行操作。部分方法如下:
l public static <T> void sort(List<T> list) // 集合元素排序
//排序前元素list集合元素 [33,11,77,55]
Collections.sort( list);
//排序后元素list集合元素 [11,33,55,77]
l public static void shuffle(List<?> list) // 集合元素存储位置打乱
//list集合元素 [11,33,55,77]
Collections.shuffle(list );
//使用shuffle方法后,集合中的元素为[77,33,11,55],每次执行该方法,集合中存储的元素位置都会随机打乱
==========================================================================
01.Map集合_概述
Collection(接口):单列集合
Map(接口):双列集合,它内部使用的"键值对"的形式存储。"键"就是为要存储的元素起的一个"名字",目的:后期可以通过名字
获取对应的元素。
键:可以是任何类型的对象,但在一个Map中,键不能重复;
值:可以是任何类型的对象。
注意:Map集合的"数据结构"都是应用在"键"上。
|--HashMap:"键"是哈希表结构。
|--LinkedHashMap:"键"是链表、哈希表结构。
02.Map集合_基本方法
1).public V put(K key, V value) : 向Map中添加一个键值对。返回值:当视图存储一个重复的键时,会用新值替换旧值,并将旧值返回。否则返回:null
2).public void clear() : 清空集合
3).public boolean containsKey(Object key) : 判断键key是否存在。
4).public boolean containsValue(Object value) : 判断值value是否存在。
5).public V get(Object key) : 获取key所对应值。
6).public boolean isEmpty() : 判断集合是否为空。
7).public V remove(Object key) : 移除key所对应的"键值对"。
8).public int size() : 获取集合大小。
9).public Set<K> keySet() : 获取所有键的集合
10).public Set<Map.Entry<K,V>> entrySet() : 获取所有键值对的集合。
03.Map集合_遍历方式1_获取键的集合【常用】
Map<String,String> map = new HashMap<>();
map.put("美猴王", "孙悟空");
map.put("天蓬元帅", "猪八戒");
map.put("卷帘大将", "沙悟净");
map.put("金蝉子", "唐三藏");
//遍历
Set<String> keys = map.keySet();
for(String k : keys){
System.out.println(k + "--" + map.get(k));
}
04.Map集合_遍历方式2_获取键值对的集合
Map<String,String> map = new HashMap<>();
map.put("美猴王", "孙悟空");//Map.Entry
map.put("天蓬元帅", "猪八戒");
map.put("卷帘大将", "沙悟净");
map.put("金蝉子", "唐三藏");
Set<Map.Entry<String,String>> es = map.entrySet();
for(Map.Entry<String, String> e : es){
String key = e.getKey();
String value = e.getValue();
System.out.println("键: " + key + " 值:" + value);
}
05.Map集合_使用自定义对象做键
注意:使用自定义对象做键,要求自定义对象必须重写:hashCode()和equals()方法
class Student{
String name;
int age;
public Student(String name, int age) {
super();
this.name = name;
this.age = age;
}
@Override
public int hashCode() {
//重写
}
@Override
public boolean equals(Object obj) {
//重写
}
}
-----------------------------------------------------------------------
main(){
Map<Student,String> map = new HashMap<>();
map.put(new Student("马蓉",20),"美女");
map.put(new Student("王博强",22),"绿巨人");
map.put(new Student("王博强",22),"小鲜肉");//会替换原值
System.out.println("集合大小:" + map.size());//3
}
06.Map集合_LinkedHashMap的使用
1).LinkedHashMap是一个有序的Map,键:链表、哈希表结构。
示例:
LinkedHashMap<String,String> map = new LinkedHashMap<>();
map.put("小三","宋喆");
map.put("美女","马蓉");
map.put("绿巨人","王博强");
System.out.println(map);//输出的顺序一定是按照存储顺序。
-------------------------------------------------------------------------------
07.可变参数
1).当一个方法的形参需要某种类型,但具体数量不固定的时候,可以选择使用"可变参数"的形式:
例如:
public static int sum(int ... nums){//编译后:public static int sum(int[] nums)
//可变参数在方法内部作为:"数组"使用
}
2).注意:
1).可变参数可以是任何类型:
int ... nums,String ... strs , Student .... stus
2).在一个方法的形参列表中,"可变参数"可以和"普通参数"共存,但可变参数只能有一个(无论是什么类型),而且必须位于
形参列表的末尾。
public static int sum(String a,String b,int ... nums){
}
3).对于可变参数,调用时可以不传参数,也可以传多个参数:
public class Demo{
public static void main(String[] args){
sum("aa","bb");//OK的,可变参数部分可以不传参数
sum("aa","bb",1,32,432,432,4,324,32,432,432,4325);//OK的,可变参数部分可以传多个int参数。
//String的参数必须要传
}
public static void sum(String a ,String b , int ... nums){
}
}
-------------------------------------------------------------------------------
08.Collections集合工具类_shuffle方法_sort方法
1).java.util.Collections(工具类):它是对Collection集合操作的一个工具类。
2).常用方法:
1).public static void shuffle(List<?> list) :
例如:
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
list.add(4);
list.add(5);
Collections.shuffle(list);
//验证
System.out.println(list);//已经乱了
2).public static <T extends Comparable<? super T>> void sort(List<T> list)
关于Comparable接口的说明:
1).String类就实现了Comparable接口;
2).String的比较就是使用Comparable接口中的compareTo()方法:
比较的结果有三种:
1).负数:当前对象小于参数对象
String s1 = "a";
String s2 = "b";
System.out.println(s1.compareTo(s2));//负数
2). 零 :当前对象与参数对象相等:
String s3 = "a";
System.out.println(s1.compareTo(s3));//零
3). 正数:当前对象大于参数对象
System.out.println(s2.compareTo(s1));//正数
例如:
List<Student> stuList = new ArrayList<>();
Collections.sort(stuList);//如果Student没有实现Comparable接口,则编译错误
List<String> strList = new ArrayList<>();
Collections.sort(strList);//OK的,String实现了Comparable接口
List<Integer> intList = new ArrayList<>();
intList.add(10);
intList.add(7);
intList.add(15);
intList.add(12);
intList.add(11);
intList.add(30);
intList.add(1);
System.out.println(intList);//[10, 7, 15, 12, 11, 30, 1]
Collections.sort(intList);//OK的,Integer实现了Comparable接口
System.out.println(intList);//[1, 7, 10, 11, 12, 15, 30]
-------------------------------------------------------------------------------
09.Arrays数组工具类_toString方法
int[] arr = {1,2,34,32,432,43};
System.out.println(arr);//数组的地址
System.out.println(Arrays.toString(arr));//[1, 2, 34, 32, 432, 43]
-------------------------------------------------------------------------------
10.数组转集合_使用Arrays数组工具类的asList方法
List<Integer> list = Arrays.<Integer>asList(10,20,7,15,8,1,432,4,32,432,43,5,23431,4);
//list.add(100);//抛异常--不能添加
//list.remove(0);//抛异常=--不能删除
list.set(0, 100);//OK的--可以修改
System.out.println(list);
说明:Arrays的asList()方法返回的是:java.lang.Arrays$ArrayList对象。这个类是Arrays的内部类,它直接继承自:AbstractList。
它内部没有重写add()和remove(),都是继承父类的,而父类的这两个方法都是"直接抛异常"。
------------------------------------------------------------------------------------------
//我们曾经自己编写的。
public static <T> List<T> show(T ... nums){
List<T> list = new ArrayList<>();
for(T t : nums){
list.add(t);
}
return list;
}
11.集合转数组_使用Collection接口中的toArray方法
List<String> list = new ArrayList<>();
list.add("aa");
list.add("bb");
list.add("cc");
//集合转数组
Object[] objArray = list.toArray();
System.out.println(Arrays.toString(objArray));
-------------------------------------------------------------------------------
总结:
01.能够说出Map集合特点
1).双列集合,使用"键值对"存储;
2).键不能重复;
3).所有数据结构都是用在"键"上。
02.使用Map集合添加方法保存数据
public V put(K key,V value):添加一个键值对。返回值:当存储相同的键时,会用新值替换旧值,并将旧值返回。否则返回:null
03.使用”键找值”的方式遍历Map集合
Map<String,String> map = new HashMap<>();
....
Set<String> keys = map.keySet();
for(String k : keys){
System.out.println(k + "--" + map.get(k));
}
04.使用”键值对”的方式遍历Map集合
Map<String,String> map = new HashMap<>();
....
Set<Map.Entry<String,String>> es = map.entrySet();
for(Map.Entry<String,String> e : es){
String key = e.getKey();
String value = e.getValue();
.....
}
05.能够使用HashMap存储自定义键值对的数据
1).自定义对象做"键",需要自定义对象重写:hashCode()和equals()方法
06.能够说出可变参数的作用
1).可以为方法指定某种数据类型,但数量不固定的形参,这就是:可变参数。调用时,实参可以不传,也可以传多个。
07.能够使用集合工具类
Collections:
1).public static void shuffle(List<?> list) :
2).public static <T extends Comparable<? super T>> void sort(List<T> list)