集合【Map、可变参数、Collections】

第1章    Map接口

1.1     Map接口概述

我们通过查看Map接口描述,发现Map接口下的集合与Collection接口下的集合,它们存储数据的形式不同,如下图。

l  Collection中的集合,元素是孤立存在的(理解为单身),向集合中存储元素采用一个个元素的方式存储。

l  Map中的集合,元素是成对存在的(理解为夫妻)。每个元素由键与值两部分组成,通过键可以找对所对应的值。

l  Collection中的集合称为单列集合,Map中的集合称为双列集合。

l  需要注意的是,Map中的集合不能包含重复的键,值可以重复;每个键只能对应一个值。

l  Map中常用的集合为HashMap集合、LinkedHashMap集合。

集合【Map、可变参数、Collections】

1.2     Map接口中常用集合概述

通过查看Map接口描述,看到Map有多个子类,这里我们主要讲解常用的HashMap集合、LinkedHashMap集合。

HashMap<K,V>:存储数据采用的哈希表结构,元素的存取顺序不能保证一致。由于要保证键的唯一、不重复,需要重写键的hashCode()方法、equals()方法。

LinkedHashMap<K,V>:HashMap下有个子类LinkedHashMap,存储数据采用的哈希表结构+链表结构。通过链表结构可以保证元素的存取顺序一致;通过哈希表结构可以保证的键的唯一、不重复,需要重写键的hashCode()方法、equals()方法。

注意:Map接口中的集合都有两个泛型变量<K,V>,在使用时,要为两个泛型变量赋予数据类型。两个泛型变量<K,V>的数据类型可以相同,也可以不同。

1.3     Map接口中的常用方法

集合【Map、可变参数、Collections】

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集合存储所有的键

集合【Map、可变参数、Collections】

2.遍历键的Set集合,得到每一个键

3.根据键,获取键所对应的值

集合【Map、可变参数、Collections】

代码演示:

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();

        //遍历存放所有keySet集合

        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)对象中获取对应的键与对应的值。

集合【Map、可变参数、Collections】

l  Entry是Map接口中提供的一个静态内部嵌套接口。

 集合【Map、可变参数、Collections】

l  getKey()方法:获取Entry对象中的键

l  getValue()方法:获取Entry对象中的值

集合【Map、可变参数、Collections】

l  entrySet()方法:用于返回Map集合中所有的键值对(Entry)对象,以Set集合形式返回。

1.6     Map集合遍历键值对方式

键值对方式:即通过集合中每个键值对(Entry)对象,获取键值对(Entry)对象中的键与值。

操作步骤与图解:

         1.获取Map集合中,所有的键值对(Entry)对象,以Set集合形式返回。

        集合【Map、可变参数、Collections】

         2.遍历包含键值对(Entry)对象的Set集合,得到每一个键值对(Entry)对象

         3.通过键值对(Entry)对象,获取Entry对象中的键与值。

        集合【Map、可变参数、Collections】

publicclass MapDemo {

    publicstaticvoid main(String[] args) {

        //创建Map对象

        Map<String, String> map = newHashMap<String,String>();

        //map中添加元素

        map.put("邓超","孙俪");

        map.put("李晨","范冰冰");

map.put("刘德华","柳岩");

        //获取Map中的所有keyvalue的对应关系

        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是集合工具类,用来对集合进行操作。部分方法如下:

集合【Map、可变参数、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)