Java进阶第七章——数据结构:Map

数据结构:Map

本章所涉及到的数据结构知识可在数据结构学习记录中学习:
咖啡ice的数据结构学习记录

1.Map常用方法

  • Map和Collection没有继承关系。

  • Map集合以key和value的方式存储数量:键值对。

    key起主导地位,value是key的附属品。

  • Map接口中常用方法:

    Map支持泛型:Map<K,V>

    向Map中放键值对:V put(K key,V value)

    通过key获取value:V get(Object key)

    清空Map:void clear()

    判断是否包含某个key:boolean containsKey(Object key)

    判断是否包含某个value:boolean containsValue(Object value)

    判断集合是否为空:boolean isEmpty()

    获取集合中所有的key,所有的健是一个Set集合:Set<K> keySet()

    获取集合中所有的value:Collection<V> values()

    通过key删除键值对:V remove(Object key)

    返回Map集合中键值个数:int size()

    将Map集合转化为Set集合:Set<Map.Entry<K,V>> entrySet()

public class MapTest {public static void main(String[] args) {//创建Map集合对象Map<Integer,String> map = new HashMap<>();//向Map集合中添加键值对map.put(1,"ice");map.put(2,"coffee");map.put(3,"is");map.put(4,"nice");//通过key获取valueSystem.out.println(map.get(2));  //coffee//获取键值对的数量System.out.println("键值对数量:" + map.size());  //键值对数量:4//通过key删除key-valuemap.remove(1);System.out.println("键值对数量:" + map.size()); //键值对数量:3//判断是否包含某个keySystem.out.println(map.containsKey(2));  //true//判断是否包含某个valueSystem.out.println(map.containsValue("coffee")); //true//获取所有的valueCollection<String> values = map.values();for (String value:values) {System.out.printf(value + " "); //coffee is nice}System.out.println();//清空mapmap.clear();System.out.println("键值对数量:" + map.size()); //键值对数量:0//判断集合是否为空System.out.println(map.isEmpty());//true}
}
  • Map集合遍历

    方法一:获取所有的key通过遍历key来遍历value。

public class MapTest {public static void main(String[] args) {Map<Integer,String> map = new HashMap<>();map.put(1,"ice");map.put(2,"coffee");map.put(3,"is");map.put(4,"nice");//遍历map集合:获取所有的key。Set<Integer> keys = map.keySet();//遍历key,通过key获取valuefor (Integer key:keys) {System.out.printf(key + "=" + map.get(key) + " "); //1=ice 2=coffee 3=is 4=nice}}
}

​ 方法二:Set<Map.Entry<K,V>> entrySet()

​ 这个方法就是把Map集合直接全部转换成Set集合。Set集合的类型是Map.Entry

public class MapTest {public static void main(String[] args) {Map<Integer,String> map = new HashMap<>();map.put(1,"ice");map.put(2,"coffee");map.put(3,"is");map.put(4,"nice");Set<Map.Entry<Integer,String>> set = map.entrySet();//遍历Set集合for (Map.Entry<Integer,String> s:set) {//System.out.printf(s.getKey() + "=" + s.getValue() + " ");System.out.printf(s + " "); //1=ice 2=coffee 3=is 4=nice }}
}

2. HashMap

  • HashMap集合底层是哈希表/散列表的数据结构。不可重复,如果key重复了,value会直接覆盖。

    常用方法:

    map.put(k,v)

    v = map.get(k)

  • 如果所有的hashCode()方法返回值固定某个值,会导致底层哈希表变成了纯单项链表。

  • 放在HashMap集合key部分的元素,以及放在HashSet集合中的元素,需要同时重写hashCode和equals方法。

  • HashMap中key部分元素不可重复。

    public class HashMapTest {public static void main(String[] args) {//Integer是key,其hashCode和equals都重写了Map<Integer,String> map = new HashMap<>();map.put(1111,"ice");map.put(6666,"coffee");map.put(7777,"is");map.put(2222,"very");map.put(2222,"good");  //key重复时,value会自动覆盖System.out.println(map.size());  //4//遍历Map集合Set<Map.Entry<Integer,String>> set = map.entrySet();for (Map.Entry<Integer,String> entry:set) {//hashMap集合中key部分元素,不可重复。System.out.printf(entry.getKey() + "=" + entry.getValue() + "  ");  //7777=is  1111=ice  6666=coffee  2222=good}}
    }
    
  • HashMap集合的个数必须是2的倍数,能够提高HashMap的存储效率。

  • HashMap集合key部分的元素是放到了HashSet集合中,所以HashSet集合的的元素需要同时重写hashCode()和equals()方法

  • 如果一个方法的equals()方法重写了,必须重写hashCode(),如果equals()方法返回的是true,hashCode()返回值必须一样。

    注:一般hashCode和equals方法在IDEA同时生成

//向Map中存取,先调hashCode再调用equals
public class HashMapTest {public static void main(String[] args) {Student s1 = new Student("coffee");Student s2 = new Student("coffee");//重写equals方法之前// System.out.println(s1.equals(s2));  false//重写equals方法之后System.out.println(s1.equals(s2));//true//没有重写hashCode()方法前,s1和s2的hashCode返回值不一样System.out.println("s1的hashCode:" + s1.hashCode());   //1163157884System.out.println("s2的hashCode:" + s2.hashCode());   //1956725890Set<Student> students = new HashSet<>();students.add(s1);students.add(s2);//按理说,s1和s2一样,两个存入hashSet中,不可重复只会有一个。//这里如果没有重写hashCoe(),则存入为两个//这里重写hashCoe(),则存入只有一个System.out.println(students.size());}
}
public class Student {private String name;public Student() {}public Student(String name) { this.name = name; }public String getName() { return name; }public void setName(String name) { this.name = name; }//重写equals方法public boolean equals(Object o) {if (o == null || !(o instanceof Student)) return false;if(o == this) return true;Student s = (Student) o;if(this.name == s.name) return true;return false;}//重写hashCode方法public int hashCode() {return Objects.hash(name);}
}
  • 放在HashMap集合key部分以及放在hashSet集合中元素,需要同时重写hashCode方法和equals方法。

  • HashMap允许key值或value值为null,但是只能有一个。

public class HashMapTest {public static void main(String[] args) {Map map = new HashMap();map.put(null,null);System.out.println(map.get(null));   //nullmap.put(null,100);System.out.println(map.get(null));  //100}
}

3. Hashtable

  • Hashtable的key和value都是不能为null的。
public class HashTableTest {public static void main(String[] args) {Map map = new Hashtable();map.put(100,null); //java.lang.NullPointerExceptionmap.put(null,"123");  //java.lang.NullPointerException}
}
  • Hashtable是线程安全的。效率较低,较少使用。

  • Properties是一个Map集合,继承Hashtable,Properties的key和value都是String。Properties被称为属性对象。

public class PropertiesTest {public static void main(String[] args) {//创建一个Properties对象Properties pro = new Properties();//Properties存方法pro.setProperty("url","jdbc:mysql://localhost:3306/ice");pro.setProperty("driver","com.mysql.jdbc.Driver");pro.setProperty("username","root");pro.setProperty("password","123");//Properties取方法System.out.println(pro.getProperty("url"));  //jdbc:mysql://localhost:3306/iceSystem.out.println(pro.getProperty("driver"));  //com.mysql.jdbc.DriverSystem.out.println(pro.getProperty("username"));  //rootSystem.out.println(pro.getProperty("password"));  //123}
}

4. TreeSet

  • TreeSet底层实际上是一个TreeMap,TreeMap集合是一个二叉树。
  • 放到TreeSet集合中元素,等同于放到TreeMap集合key部分。
  • TreeSet中集合不可重复,但是可以按照元素大小自动排序。
public class TreeSetTest	 {public static void main(String[] args) {//创建一个TreeSet集合TreeSet<String> ts = new TreeSet<>();//添加Stringts.add("ice");ts.add("coffee");ts.add("is");ts.add("very");ts.add("good");for (String t:ts) {System.out.printf(t + " ");  //coffee good ice is very}System.out.println();TreeSet<Integer> ts2 = new TreeSet<>();ts2.add(100);ts2.add(254);ts2.add(54);ts2.add(21);ts2.add(100);for (Integer t:ts2) {System.out.printf(t + " ");  //21 54 100 254}}
}
  • TreeSet无法对自定义类型进行排序
public class TreeSetTest {public static void main(String[] args) {Person p1 = new Person(15);TreeSet<Person> persons = new TreeSet<>();persons.add(p1);  //Exception in thread "main" java.lang.ClassCastException: collection.Person cannot be cast to java.lang.Comparable}
}
class Person{int age;public Person(int age){this.age = age;}
}
  • 自定义类型需要排序时,需要实现Comparable接口。Comparable接口中需要实现compareTo()方法。

    compareTo()方法:

    返回0表示相同,value会覆盖

    返回<0,会在左子树上查找

    返回>0,会在右子树上查找

public class TreeSetTest {public static void main(String[] args) {Cutomer c1 = new Cutomer(32);Cutomer c2 = new Cutomer(26);Cutomer c3 = new Cutomer(45);Cutomer c4 = new Cutomer(23);TreeSet<Cutomer> cs = new TreeSet<>();cs.add(c1);cs.add(c2);cs.add(c3);cs.add(c4);for (Cutomer c:cs) {System.out.printf(c.age + " ");  //23 26 32 45 }}
}
//放在TreeSet集合中,需要实现java.lang.Comparable接口
//并实现compareTo方法,equals可以不写
class Cutomer implements Comparable<Cutomer>{int age;public Cutomer(int age){this.age = age;}//编写比较逻辑,或者比较规则。@Overridepublic int compareTo(Cutomer c) {return this.age - c.age;  //从小到大//return  c.age - this.age;  从大到小}
}
  • TreeSet集合中元素可排序的第二种方式:使用比较器方式。这种方式适用于写多个比较规则。
public class TreeSetTest03 {public static void main(String[] args) {//创建TreeSet集合时,需要使用这个比较器TreeSet<Cutomer> cus = new TreeSet<>(new CutomerComparator());//传一个比较器进去cus.add(new Cutomer(23));cus.add(new Cutomer(45));for (Cutomer c:cus) {System.out.printf(c + " ");  //Cutomer{age=23} Cutomer{age=45} }}
}
class Cutomer{int age;public Cutomer(int age){ this.age = age; }@Overridepublic String toString() { return "Cutomer{" + "age=" + age + '}'; }
}
//单独编写比较器,比较器实现java.util.Comparator接口
class CutomerComparator implements Comparator<Cutomer> {@Overridepublic int compare(Cutomer o1, Cutomer o2) {//指定比较规则,按照年龄排序return o1.age - o2.age;}
}

5.Collections工具类

  • 集合接口:java.util.Collection

  • 方便集合操作,集合工具类:java.util.Collections

    集合工具类常用方法:

    将集合转换成线程安全:synchronizedList()

    集合排序:sort()

public class CollectionsTest01 {public static void main(String[] args) {//ArrayList集合不是线程安全的List<String> list = new ArrayList<>();//变成线程安全的Collections.synchronizedList(list);//排序list.add("abf");list.add("abc");list.add("abe");list.add("aba");Collections.sort(list);for (String s:list) {System.out.printf(s + " ");  //aba abc abe abf}System.out.println();//对于自定义类型的排序,需要实现Comparable接口List<Cutomer2> cus2 = new ArrayList<>();cus2.add(new Cutomer2(30));cus2.add(new Cutomer2(20));cus2.add(new Cutomer2(25));Collections.sort(cus2);for (Cutomer2 c:cus2) {System.out.printf(c.age + " ");  //20 25 30}System.out.println();//Set集合如果想要用sort方法进行排序,需要将Set集合转换成list集合Set<String> set = new HashSet<>();set.add("king");set.add("king2");set.add("king3");List<String> mylist = new ArrayList<>(set);Collections.sort(mylist);for (String s:mylist) {System.out.printf(s + " ");//king king2 king3 }}
}
class Cutomer2 implements Comparable<Cutomer2>{int age;public Cutomer2(int age){this.age = age;}//编写比较逻辑,或者比较规则。@Overridepublic int compareTo(Cutomer2 c) {return this.age - c.age;  //从小到大//return  c.age - this.age;  从大到小}
}

——本章节为个人学习笔记。学习视频为动力节点Java零基础教程视频:动力节点—JAVA零基础教程视频