java-集合二哥-Map

java-集合二哥-Map

二哥与大哥的不同(Map接口与Collection接口下的集合存储数据的形式不同):

  • Collection中的集合,元素是孤立存在的(单身狗),向集合中存储元素采用一个个元素的方式存储
  • Map中的集合,元素是成对存在的(夫妻档),每个元素由键与值两部分组成,通过键可以找到对应的值
  • Collection中的集合称为单列集合,Map中的集合称为双列集合
  • Map(映射关系的键值对)中的集合不能包含重复的键,值可以重复,每个键只能对应一个值
  • Map中常用的集合有:HashMap,LinkedHashMap
  • HashMap<K,V>:存储数据采用的哈希表结构,元素的存取顺序不能保证一致,由于要保证键的唯一、不重复,需要重写键的hashCode()方法,equals()方法
  • LinkedHashMap<K,V>:HashMap的子类,存储数据采用的是哈希表结构+链表结构,通过链表结构可以保证元素的存取顺序一致,通过哈希表结构可以保证键的唯一、不重复,同样需要重写键的hashCode()方法,equals()方法
  • Tips:Map接口中的集合都有两个泛型变量<K,V>,在使用时要为两个泛型变量赋予数据类型,两个数据类型可以相同,也可以不同

Map接口中的常用方法

使用Map接口的实现类HashMap学习方法:put get remove

package 集合;
import java.util.HashMap;
import java.util.Map;
public class MapDemo {
    public static void main(String[] args) {
        /**
         * 将键值对存储到集合中
         * V put(K,V) K作为键的对象,V作为值的对象
         * 如果存储的是重复的K,那么覆盖原有的V
         * 返回值一般是null,但是当存储重复键的时候,会返回被覆盖的值
         */
        function();

        /**
         * 1.通过键对象,获取值对象
         * V get(K) ,如果集合中不存在键K,返回null
         * 2.移除集合中的键值对,并返回被移除之前的值
         * V remove(K) ,如果集合中不存在键K,返回null
         */
        function_1();

    }

    private static void function_1() {
        System.out.println("get方法+remove方法输出如下:-----------------");
        //创建集合对象,整数作为键的对象,字符串作为值的对象
        Map<Integer,String> map = new HashMap<Integer, String>();
        map.put(1,"one");
        map.put(2,"two");
        map.put(3,"three");
        System.out.println("构造的map:"+map);

        String value = map.get(1);
        System.out.println("get存在的键(1):"+value);
        System.out.println("get不存在的键(100):"+map.get(100));

        String value_removed = map.remove(1);
        System.out.println("remove存在的键(1):"+value_removed);
        System.out.println("remove不存在的键(100):"+map.remove(100));

        System.out.println("remove后的map:"+map);
    }

    public static void function(){
        System.out.println("put方法输出如下:-----------------");
        //创建集合对象,HashMap,存储对象,键是字符串,值是整数
        Map<String,Integer> map = new HashMap<String, Integer>();
        Integer i = map.put("one",1);
        System.out.println("一般情况下put的返回值:"+i);

        map.put("two",2);

        map.put("three",3);
        System.out.println("构造的map:"+map);
        Integer cover = map.put("three",5); //存储重复的键,将原有的值覆盖,并返回被覆盖的值
        System.out.println("存储重复键的情况下,返回被覆盖的值:"+cover);

        System.out.println("put重复键(three)后的map:"+map);
        System.out.println();
    }
}
//输出
put方法输出如下:-----------------
一般情况下put的返回值:null
构造的map:{one=1, two=2, three=3}
存储重复键的情况下,返回被覆盖的值:3
put重复键(three)后的map:{one=1, two=2, three=5}

get方法+remove方法输出如下:-----------------
构造的map:{1=one, 2=two, 3=three}
get存在的键(1):one
get不存在的键(100):null
remove存在的键(1):one
remove不存在的键(100):null
remove后的map:{2=two, 3=three}

Map集合的遍历

  • 键找值:键是唯一的,通过方法keySet()可以得到Map集合中所有的键(Set< key >),接着通过get(Object key)方法,按照指定的键从Map集合中找到对应的值
package 集合;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
public class MapIteratorDemo {
    public static void main(String[] args) {
        function();
    }
    private static void function() {
        /**
         * 1.调用Map集合中的方法keySet,所有的键存储到Set集合中
         * 2.遍历Set集合,获取出Set集合中的所有元素(Map中的键)
         * 3.调用Map集合中的方法get,通过键获取到值
         */
        //创建集合对象,HashMap,存储对象,键是字符串,值是整数
        Map<String,Integer> map = new HashMap<String, Integer>();
        map.put("one",1);
        map.put("two",2);
        map.put("three",3);
        map.put("four",4);
        map.put("five",5);

        Set<String> set  =map.keySet();
        // class java.util.HashMap$KeySet $是内部类的标记,keySet返回的Set是HashMap的内部类
        System.out.println(set.getClass()); //getClass()方法返回类的全名
        System.out.println("Iterator遍历Set如下:-------------------------");
        Iterator<String> it = set.iterator();
        while(it.hasNext()){
            String key = it.next();
            Integer value = map.get(key);
            System.out.println("key:"+key+" value:"+value);
        }

        System.out.println("增强for遍历Set如下:-------------------------");
        for(String key:set){
            Integer value = map.get(key);
            System.out.println("key:"+key+" value:"+value);
        }
    }
}

输出如下:

class java.util.HashMap$KeySet
Iterator遍历Set如下:-------------------------
key:four value:4
key:one value:1
key:two value:2
key:three value:3
key:five value:5
增强for遍历Set如下:-------------------------
key:four value:4
key:one value:1
key:two value:2
key:three value:3
key:five value:5

Map集合中的keySet()方法返回的Set集合类型并不是HashSet,而是java.util.HashMap$KeySet,是HashMap的内部类

  • Entry 键值对对象:在Map类设计时,提供了一个静态的内部嵌套接口(Entry),Entry将键值对的对应关系封装成了对象,即键值对对象,这样我们在遍历Map集合时,就可以从每一个键值对对象中获取对应的键与对应的值(就像夫妻双方的结婚证一样)
  • 通过键值对:entrySet()方法得到一个包含多个键值对的Set集合(set< Entry<key,value> >
  • 接着通过Entry接口中的getKey()getValue()方法获取键和值
package 集合;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
public class MapIteratorDemo {
    public static void main(String[] args) {
        function_entry();
    }
    private static void function_entry() {
        /**
         * 1.调用Map集合中的方法entrySet,将所有的键值对对象存储到Set集合中 Set< Entry<K,V> >
         * 2.遍历Set集合,获取出Set集合中的所有元素(键值对对象)
         * 3.通过键值对对象方法getkey,getValue获取键值对
         */
        //创建集合对象,HashMap,存储对象,键是字符串,值是整数
        Map<String,Integer> map = new HashMap<String, Integer>();
        map.put("one",1);
        map.put("two",2);
        map.put("three",3);
        map.put("four",4);
        map.put("five",5);
        //创建内部类对象,外部类.内部类 = new
        Set<Map.Entry<String,Integer>> set = map.entrySet();
        System.out.println(set.getClass());
        System.out.println("Iterator遍历Set如下:-------------------------");

        Iterator<Map.Entry<String,Integer>> it = set.iterator();
        while (it.hasNext()){
            Map.Entry<String,Integer> entry = it.next();
            String key = entry.getKey();
            Integer value = entry.getValue();
            System.out.println("key:"+key+" value:"+value);
        }

        System.out.println("增强for遍历Set如下:-------------------------");
        for(Map.Entry<String,Integer> entry:set){
            System.out.println("key:"+entry.getKey()+" value:"+entry.getValue());
        }
    }   
}

输出如下:

class java.util.HashMap$EntrySet
Iterator遍历Set如下:-------------------------
key:four value:4
key:one value:1
key:two value:2
key:three value:3
key:five value:5
增强for遍历Set如下:-------------------------
key:four value:4
key:one value:1
key:two value:2
key:three value:3
key:five value:5

Map集合中的entrySet()方法返回的Set集合类型是java.util.HashMap$EntrySet,是HashMap的内部类
Tips:增强for循环是不能直接遍历Map集合的,这里直接遍历的是Set集合,Map集合遍历的两种方式都转为了对Set集合的遍历,只能说是间接的遍历了Map集合

Map存储自定义类型数据,作为值和作为键的两种方式,当自定义类型作为键时,为了保证键的唯一性,需要重写自定义类型的hashCode()equals()方法,如下

package 集合;
import java.util.HashMap;
import java.util.Map;
public class HashMapDemo {
    public static void main(String[] args) {
        /**
         * HashMap 存储自定义的对象Person,作为值出现
         * 键的对象是字符串,可以保证唯一性
         */
        //function();

        /**
         * HashMap 存储自定义的对象Person,作为键出现
         * 键的对象是Person类型,值是字符串
         * 保证键的唯一性,存储到键的对象,重写hashCode和equals方法
         */
        function_key();
    }

    public static void function_key() {
        HashMap<Person,String> hashMap = new HashMap<Person,String>();
        hashMap.put(new Person("张三",20),"one");
        hashMap.put(new Person("李四",21),"two");
        hashMap.put(new Person("王五",22),"three");
        hashMap.put(new Person("王五",22),"three");

        for(Person key:hashMap.keySet()){
            String value = hashMap.get(key);
            System.out.println("key:"+key+" value:"+value);
        }

    }

    public static void function(){
        HashMap<String,Person> hashMap = new HashMap<String, Person>();
        hashMap.put("one",new Person("张三",20));
        hashMap.put("two",new Person("李四",21));
        hashMap.put("three",new Person("王五",22));
        hashMap.put("four",new Person("林一",19));
        hashMap.put("five",new Person("司徒",18));

        for(String key:hashMap.keySet()){
            Person value = hashMap.get(key);
            System.out.println("key:"+key+" value:"+value);
        }
        System.out.println("--------------------------");
        for(Map.Entry<String,Person> entry:hashMap.entrySet()){
            String key = entry.getKey();
            Person value = entry.getValue();
            System.out.println("key:"+key+" value:"+value);
        }
    }
}
//Person类
package 集合;
/**
 * 如果子类重写了父类的方法,哈希值就变成自定义的
 * 存储到hashSet的依据
 */
public class Person {
    private String name;
    private int age;
    /**
     * 对象存储哈希表,去掉重复元素,依据对象自己的hashCode,equals重写目标
     * 使对象中属性值name,age如果属性值相同,得到相同的哈希值
     * 哈希值的计算参考String,字符串的每个字符都参与计算 31*原来的计算结果 + 字符ASCII码值
     * name属性本身就是字符串,简单 name.hashCode() + age
     */
    @Override
    public int hashCode(){
        //return name.hashCode()+age; // b,10 和 a,11 哈希值相同都是108,所以需要重写equals方法
        //降低出现如上相同哈希值的概率,改进如下
        return name.hashCode()+age*2;
    }
    @Override
    public boolean equals(Object object){
        if(this == object){
            return true;
        }
        if(object == null){
            return false;
        }
        if(object instanceof Person) { //判断一个对象是否是该类的实例
            Person person = (Person) object; //是的话就可以强制转换
            return name.equals(person.name) && age == person.age;
        }
        return false;
    }
    public Person(){}
    public Person(String name,int age) {
        this.name = name;
        this.age = age;
    }
    @Override
    public String toString() {
        return "Person{" + "name='" + name + '\'' + ", age=" + age + '}';
    }
}

LinkedHashMap继承HashMap,只不过它保证了迭代的顺序,即以什么顺序存进去的,就会以什么顺序取出来,用法与HashMap一致,就不做演示啦!(之前所提到的集合都是线程不安全的,运行速度快)

Map接口实现类:Hashtable,底层数据结构也是哈希表,特点和HashMap是一样的,但是需要注意的是,Hashtable是线程安全的(方法实现是同步的,开销比较大),运行速度较慢,Hashtable的命运和Vector(被ArrayList取代)是一样的,从JDK1.2开始,被更先进的HashMap所取代,除了线程是否安全这一点不同外,Hashtable是不允许存储null值和null键的,而HashMap允许存储null值和null键
虽然HashTable被抛弃了,但是他的孩子,子类Properties依然活跃在开发的舞台,Properties可以和IO流共同配合实现数据的持久存储

发布了22 篇原创文章 · 获赞 21 · 访问量 7008

猜你喜欢

转载自blog.csdn.net/weixin_43108122/article/details/101054074