Java Map接口和常用工具类

在这里插入图片描述

1.Map接口常用方法

Interface Map<K,V>
java.util.Map接口中常用的方法
1.Map和 ColLection没有继关系。
2.Map集合key和value的方式存储存数据:键值对
key和value都是引用数据类型。
key和value都是存储对象的内存地址。
key起到主导的地位, value是key的一个附属品。
3.Map接口中常用方法
v put(K key, v value)向Map集合中添加键值对
v get(Object key)通过key获取 value
void clear()清空Map集合
boolean containsKey( bject key)判断Map中是否包含某个key
boolean containsValue( Object value)判断Map中是否包含某个 value
boolean isEmpty()判断Map集合中元素个数是否为0
Set keySet()获Map集合所有的key(所有的键是一个Set集合)
V remove( Object key) 通边key删键值对
int size()获取Map集合中键值对的个数。
Collection values() 获动Map集合中所有的value,返回一个 Collection
Set<Map.Entry<K,V>> entrySet() 将Map集合转换为Set集合
在这里插入图片描述
没看到的是map中的静态内部类

一.静态内部类(了解entrySet()方法)

Set<Map.Entry<K,V>> entrySet() 
返回一个 Set视图的映射包含在这个Mapimport java.util.HashSet;
import java.util.Set;

public class MyClass{
    
    
    public static void main(String[] args) {
    
    
        //类名叫做MyClass.InnerClass
        MyClass.InnerClass.m1();
        //创建静态内部类对象
        MyClass.InnerClass mi=new MyClass.InnerClass();
        mi.m2();
        //给一个Set集合
        //该Set集合中存的对象是: Myclass.Innerclass类型
        Set<MyClass.InnerClass> set=new HashSet<>();
        //这个Set集合存储的是字符串对象
        Set<String> set2=new HashSet<>();
        Set<MyMap.MyEntry<Integer,String>> set3=new HashSet<>();
        }
    static class InnerClass{
    
    
        public static void m1(){
    
    
            System.out.println("静态内部类m1方法");
        }
        public void m2(){
    
    
            System.out.println("静态内部类的实例方法执行");
        }

    }
}
class MyMap{
    
    
    public static class MyEntry<K,V>{
    
    

    }
}

静态内部类m1方法
静态内部类的实例方法执行

二.Map接口常用方法

import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

public class MapTest01 {
    
    
    public static void main(String[] args) {
    
    
        //创建Map集合对象
        Map<Integer,String> map=new HashMap<>();
        //向Map集合添加键值对
        map.put(1,"lupeng");        //在这里进行了自动装箱
        map.put(2,"zhangsan");
        map.put(3,"zhangyinying");
        map.put(4,"wangcan");
        //通过key获取value
        System.out.println(map.get(3));

        //获取键值对的数量
        System.out.println(map.size());
        //通过key删除key-value
        map.remove(2);
        System.out.println(map.size());
        //判断是否包含某个key
        //contains方法底层调用的部是 equals进行比对的,所以自定义的类型需要重写 equals方法。
        System.out.println(map.containsKey(2));
        //判断是否包含某个value
        System.out.println(map.containsValue("zhangyinying"));
        //获取所有的value
        System.out.println("+++++++++++++");
        Collection<String> values=map.values();
        for (String data:values){
    
    
            System.out.println(data);
        }
        //清空Map集合
        map.clear();
        //判断是否为空
        System.out.println(map.isEmpty());
    }
}

zhangyinying
4
3
false
true
+++++++++++++
lupeng
zhangyinying
wangcan
true

三.遍历Map集合

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

public class HashSet01{
    
    
    public static void main(String[] args) {
    
    
        //创建Map集合对象
        Map<Integer,String> map=new HashMap<>();
        //向Map集合添加键值对
        map.put(1,"zhansan");//使用自动装箱
        map.put(2,"yinying");
        map.put(3,"lupeng");
        map.put(4,"wangcan");
        //重复便覆盖HashMap
        map.put(1,"huyiwen");
        //Set<Integer> set=map.keySet();//获取Map集合所有的key(所有的键是一个Set集合)

       // Iterator<Integer> it= set.iterator();
/*        while (it.hasNext()){
            Integer key=it.next();
            System.out.println(key+"="+map.get(key));
        }*/
/*        for (Integer key:set){
            System.out.println(key+"="+map.get(key));
        }*///上述效率较低,通过key获取value

        //第二种方式:Set<Map.Entry<K,V>> entrySet()
        //以上这个方法是把Map集台接全部转换成Set集合。
        //Set集合中元素的类型是: Map.Entry
        Set<Map.Entry<Integer,String>> set=map.entrySet();
        Iterator<Map.Entry<Integer,String>> iterator2=set.iterator();
        while(iterator2.hasNext()){
    
    
            Map.Entry<Integer,String> node= iterator2.next();
            Integer key=node.getKey();
            String value=node.getValue();
            System.out.println(key+"="+value);
        }
        for(Map.Entry<Integer,String> node:set){
    
    
            System.out.println(node.getKey()+"---"+node.getValue());
        }
    }
}

1=huyiwen
2=yinying
3=lupeng
4=wangcan
1—huyiwen
2—yinying
3—lupeng
4—wangcan

Map集合转换成Set集合entrySet()方法
node

1.哈希表数据结构

![在这里插入图片描述](https://img-blog.csdnimg.cn/627f600560ac44aebe99f53e3e8aa3c9.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2xwYmxvZw==,size_16,color_FFFFFF,t_70

HashMap集合:
1、 HashMap集合底层是哈希表/散列表的数据结构。
2、哈希表是一个怎样的数据结构呢?
哈希表是一个数组和单向链表的结合体。
数组:在查询方面效率很高,随机增删方面效率很低。
单向链表:在随机增删方面效率较高,在查询方面效率很低
哈希表将以上的两种数据结构融合在一起,充分发挥它们各自的优点。
HashMap集合底层的源代码:
public class HashMap{
// HashMap底层实际上就是一个数组。(一维数组)
Node<k, v> table;
//静态的内部类HashMan.Node
static class Node<k, v>{
final int hash;∥/哈希值(哈希值是key的 hashcode()方法的执行结果。hash值通过哈带函数/箅法,可以转换存储成数组的下标。)
final k key;//存储到Map集合中的那个key
V value;//存储到Map集合中的那个 value
Node<K,v>next; //下一个节点的内存地址
哈希表/散列表:一维数组,这个数组中每一个元素是一个单向链表。(数组和链表的结合体)
4、最主要掌握的是:
map. put(k, v)
v= map. get(k)
以上这两个方法的实现原理,是必须掌握的。
5、 HashMap集合的key部分特点:
无序,不可重复。
为什么无序?因为不一定挂到哪个单向链表上
不可重复是怎么保证的?equals方法来保证HashMap集合的key不可重复。
如果key重复了,value会覆盖。
放在HashMap集合key部分的元素其实就是放到HashSet集合中了。
所以Hashset集合中的元素也需要同时重写hashCode()+ equals()方法。
6、哈希表 HashMap使用不当时无法发挥性能!
假设将所有的 hashCode()方法返回值固定为某个值,那么会导致底层哈带表变成了纯单向链表。这种情况我们成为:散列分布不均匀。
什么是散列分布均匀?
假设有100个元素,10个单向链表,那么每个单向链表上有10个节点,这是最好的是散列分布均匀的。
假设将所有的 hashCode()方法返回值都设定为不一样的值,可以吗,有什么问题?
不行,因为这样的话导致底层哈希表就成为一维数组了,没有链表的概念了也是散列分布不均匀,散列分布均匀需要你重写hashCode()方法时有一定的技巧。
7、重点:放HashMp集合key部分的元素,似及放在Hashset集合中的元素,需要同时重马 hashcode和 equals方法。
8、 HashMap集台的默认初始化容量是16,默认加载因子是0.75
这个默认加载因子是当 HashMap集合底层数组的容量达到5%的时候,数组开始扩容。
重点,记住:阳shM集合初始化容量必须是2的倍数,这也是宫方推荐的
这是因为达到散列均匀,为了提高 HashMap集合的存取效率,所必须的

哈希表表或散列表数据结构

在这里插入图片描述

2.用户自定义对象需重写hashcode和equals方法(同时对于HashSet也是一样,底层是HashMap)

Java 自定义对象作为 Map 的 key 时,需重写 equals() 和 hashCode() 方法
//之前在key中String和Integer类都重写了equals,所以不需要重写equals和hashcode

import java.util.HashSet;
import java.util.Set;
/*
1.向Map集合中存,以及从Map集合中取,都是先调用key的HashCode方法,然后再调用equals方法!
        equals方法有可能调用,也有可能不调用。
    拿put(k,V)举例,什么时候 equals不会调用?
        k.hashcode()方法返回哈希值,
        哈希值经过哈希算法转换成数组下标
        数组下标位置上如果是null, equals不需要执行。
    拿get(k)举例,什么时候 equals不会调用?
        k. hashcode()方法返回哈带值,
        哈带值经过哈带算法转换成数组下标。
        数组下标位置上如果是nuLL, equals不需要执行。
2.注意:如果一个类的 equals方法重写了,那么 hashCode()方法必须重写。
并且 equals方法返回如果是true, hashcode()方法返回的值必须一样。
equals方法返回true表示两个对象相同,在同一个单向链表上比较。
那么对于同一个单向链表上的节点来说,他们的哈希值部是相同的
所以hashcode()方法的返回值也应该相同。
3.hashcode()方法和equals()方法不用研究了,接使用IDEA工具生成,但是这两个方法需要同时生成。
4.终极结论:
放在HashMap集合Key部分的,以及放在HashSet集合中的元素,需要同时重写hashCode方法和equals方法。
5.对于哈希表数据结构来说
如果01和02的hash值相同,一定是放到同一个单向链表上。
当然如果01和2的hash值不同,但由于哈带算法执行结束之后转换的数组下标可能相同,此时会发生哈希碰撞。*/

public class Student {
    
    

    // 姓名
    private String stuNm;

    // 年龄
    private String age;

    // 构造函数
    public Student(String stuNm, String age) {
    
    
        this.stuNm = stuNm;
        this.age = age;
    }

    @Override
    public boolean equals(Object o) {
    
    
        if (this == o) return true;
        if (!(o instanceof Student)) return false;

        Student student = (Student) o;

        if (stuNm != null ? !stuNm.equals(student.stuNm) : student.stuNm != null) return false;
        return age != null ? age.equals(student.age) : student.age == null;
    }

    @Override
    public int hashCode() {
    
    
        int result = stuNm != null ? stuNm.hashCode() : 0;
        result = 31 * result + (age != null ? age.hashCode() : 0);
        return result;
    }
}


import java.util.Map;

public class Test {
    
    

    public static void main(String[] args) {
    
    

        Map<Student, String> map = new HashMap<>();

        Student stuA = new Student("张三", "20");
        map.put(stuA, "95");

        Student stuB = new Student("张三", "20");
        map.put(stuB, "93");

        System.out.println(map.get(stuA));      // 93
        System.out.println(map.get(stuB));      // 93
		System.out.println("stuA的hashcode是"+stuA.hashCode());
        System.out.println("stuB的hashcode是"+stuB.hashCode());
        Student stuC = new Student("张三", "20");
        System.out.println(map.get(stuC));      // 93
        System.out.println(stuA.equals(stuC));  // true
    }
}

93
93
stuA的hashcode是24023157
stuB的hashcode是24023157
93
true

3.HashMap和HashTable的区别

Hashtable的key可以为nuL吗?
Hashtable的key和aLue都是不能为null的。
HashMap集台的key和value都是可以为nuLL的
Hashtable方法都带有 synchronized:线程安全的。
线程安全有其它的方案,这个 Hashtable对线程的处理
导致效率较低,使用较少.

import java.util.Hashtable;
import java.util.Map;

public class HashtableTest01 {
    
    
    public static void main(String[] args) {
    
    
        Map map=new Hashtable();
        //map.put(null,11);
        map.put(100,null);
    }
}

4.Properties类

目前只需要掌握Properties属性类对象的相关方法即可
Properties是一Map集合,继Hashtable, Properties的key和value都是String类型。
Properties被称为属性类对象。
Properties是线程安全的

import java.util.Properties;

public class PropertiesTest01 {
    
    
    public static void main(String[] args) {
    
    
    //创建一个Properties对象
        Properties pro=new Properties();
  //需要掌握Properties的两个方法,一个存、一个取      
        pro.setProperty("lupeng1","root123");
        pro.setProperty("lupeng2","root12353");
        pro.setProperty("lupeng3","root12433");
        pro.setProperty("lupeng4","root45123");
//通过key获取value
        String username1=pro.getProperty("lupeng1");
        String username2=pro.getProperty("lupeng2");
        String username3=pro.getProperty("lupeng3");
        String username4=pro.getProperty("lupefsng4");

        System.out.println(username1);
        System.out.println(username2);
        System.out.println(username3);
        System.out.println(username4);

    }
}

root123
root12353
root12433
null

二.TreeMap集合

Java异常ClassCastException

转载

1.TreeSet无法对自定义类型排序

对自定义的类型来说, Treeset可以排序吗?
以下程序中对于 Person类型来说,无法排序。因为没有指定Person对象之间的比较规则。
谁大谁小并没有说明啊。
以下程序运行的时候出现了这个异常
java.lang.ClassCastException;
class com.javase.collection.HashSet.Person cannot be cast to class java.lang.Comparable
出现这个异常的原因
Person:类没有实现java.lang. Comparable接口

2.TreeMap用户自定义比较(两种方式)

1.用户自定义类型实现Comparable接口

/放在 Treeset集合中的元素需要实现iava.lang. Comparable口
//并且实现 compareTo方法。 equals可以不写。

import java.util.Iterator;
import java.util.TreeSet;

public class TreeSetTest05 {
    
    
    public static void main(String[] args) {
    
    
        TreeSet<Vip> vips=new TreeSet<>();
        vips.add(new Vip("zhangsan",20)); //添加指定元素到集合中
        vips.add(new Vip("zhangyinying",20));
        vips.add(new Vip("lupeng",19));
        vips.add(new Vip("wangcan",20));
        //使用迭代器
        Iterator it=vips.iterator();
        while (it.hasNext()){
    
    
            System.out.println(it.next());
        }
        vips.add(new Vip("fuck",19));
        System.out.println("+++++++++++++++++++");
        //增强for
        for (Vip vip:
             vips) {
    
    
            System.out.println(vip);
        }
    }
}
class Vip implements Comparable<Vip>{
    
    
    String name;
    int age;

    public Vip() {
    
    
    }

    public Vip(String name, int age) {
    
    
        this.name = name;
        this.age = age;
    }
/*    需要在这个方法中编写比较的逻辑,或者说比较的规则,按照什么进行比较!
 k.compareTo(t key)
拿着参数和集合中的每一个进行比较,返回值可能是>0 <0 =0*/
    @Override
    public int compareTo(Vip v) {
    
    
        if (this.age==v.age){
    
    
            return this.name.compareTo(v.name);
        }else {
    
    
            return this.age-v.age;
        }
    }

    @Override
    public String toString() {
    
    
        return "Vip{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

Vip{name=‘lupeng’, age=19}
Vip{name=‘wangcan’, age=20}
Vip{name=‘zhangsan’, age=20}
Vip{name=‘zhangyinying’, age=20}
+++++++++++++++++++
Vip{name=‘fuck’, age=19}
Vip{name=‘lupeng’, age=19}
Vip{name=‘wangcan’, age=20}
Vip{name=‘zhangsan’, age=20}
Vip{name=‘zhangyinying’, age=20}

平衡二叉树数据结构在这里插入图片描述

2.实现比较器接口

TreeSet集合中元素可排序的第二种方式:使用比较器的方式
最终的结论:
放到 Treeset-或者TreeMap集合key部分的元素要想做到排序包括两种方式:
第一种:放在集合中的元素实现java.lang. Comparable接口。
第二种:在构造TreeSet或者 TreeMap集合的时候给它传一个比较器对象。
Comparable和 Comparator怎么选择呢?
当比较规则不会发生改交的时候,或者说当比较规则只有1个的时候,建议实现 comparable接口。
如果比较规则有多个,并且需要多个比较规则之间频繁切换,建议使用 Comparator接口。
Comparator接口的设计符台OCP原则。

import java.util.Comparator;
import java.util.TreeSet;

public class TreeSetTest06 {
    
    
    public static void main(String[] args) {
    
    
        //实现接口compare
        TreeSet<Wugai> wugais=new TreeSet<>(new WuGaiComparetor());
        //采用匿名内部类
       /* TreeSet<Wugai> wugais = new TreeSet<>(new Comparator<Wugai>() {
            @Override
            public int compare(Wugai o1, Wugai o2) {
                return o1.age - o2.age;
            }
        });*/
        wugais.add(new Wugai(423));
        wugais.add(new Wugai(234));
        wugais.add(new Wugai(35));
        for (Wugai wugai :
                wugais) {
    
    
            System.out.println(wugai);
        }
    }
}
class Wugai  {
    
    
    int age;

    public Wugai(int age) {
    
    
        this.age = age;
    }

    @Override
    public String toString() {
    
    
        return "Wugai{" +
                "age=" + age +
                '}';
    }

}
//单独在这里编写了一个比较器
//比较器实现java.util.Comparator接口.(Comparable是java.lang包下的。Comparator是java.util包下的)
class WuGaiComparetor implements Comparator<Wugai>{
    
    

    @Override
    public int compare(Wugai o1, Wugai o2) {
    
    
        return o1.age-o2.age;
    }
}

Wugai{age=35}
Wugai{age=234}
Wugai{age=423}

3.Collections工具类

import java.util.*;

public class CollectionTest {
    
    
    public static void main(String[] args) {
    
    
        //ArrayList集合不是线程安全的
        List<String> list=new ArrayList<>();
        //变成线程安全的
        Collections.synchronizedList(list);
        list.add("aba");
        list.add("aba");
        list.add("abd");
        list.add("abx");
        list.add("abc");
        Collections.sort(list);
        for (String data:
             list) {
    
    
            System.out.println(data);
        }
      Set<String> set=new HashSet<>();
        set.add("lupeng2");
        set.add("lupeng4");
        set.add("lupeng1");
        set.add("lupeng3");
        //将set集合转换为list集合
        List<String> myList=new ArrayList<>(set);
        //可以使set集合变成list集合进行排序
        Collections.sort(myList);
        for (String s:myList){
    
    
            System.out.println(s);
        }
    }
}
class Wugui{
    
    
    int age;

    public Wugui(int age) {
    
    
        this.age = age;
    }
}

aba
aba
abc
abd
abx
lupeng1
lupeng2
lupeng3
lupeng4

猜你喜欢

转载自blog.csdn.net/lpblog/article/details/113915625