Java学习笔记(六)

Java学习笔记(六)

List集合

  • java.util.List接口继承自Collection接口,是单列集合的一个重要分支,习惯性的会将实现了List接口的对象称为List集合,在List集合中允许出现重复的元素,所有的元素是以一种线性方式进行存储的,在程序中可以通过索引来访问集合中的指定元素。另外,List集合还有一个特点就是元素有序,即元素的存入顺序和取出顺序一致。

List接口的特点:

  1. 元素存取有序的集合
  2. 带有索引的集合
  3. 集合中可以有重复元素

常用方法(特有)

  • public void add(int index,E element):将指定的元素,添加到集合中的指定位置上
  • public E get(int index):返回集合中指定位置的元素
  • public E remove(int index):移除列表中指定位置的元素,返回的是被移除的元素
  • public E set(int index,E element):用指定的元素替换集合中指定位置的元素,返回值为被替换的元素

注意:操作索引的时候,一定要防止索引越界异常

  • IndexOutOfBoundException:集合索引越界异常
  • ArrayIndexOutOfBoundException:数组索引越界异常
  • StringIndexOutOfBoundException:字符串索引越界异常
public class Test {
    public static void main(String[] args) {
        List<String> list  = new ArrayList<>();
        list.add("a");
        list.add("b");
        list.add("c");
        System.out.println(list);//[a, b, c]
        String s = list.get(1);
        System.out.println(s);//b
        String removeE = list.remove(2);
        System.out.println(removeE);//c
        list.add(1,"thomas");
        System.out.println(list);//[a, thomas, b]
        String result = list.set(2, "hello");//b
        System.out.println(list);//[a, thomas, hello]
        //集合的遍历
        for (String s1 : list) {
            System.out.println(s1);
        }
        for (int i = 0; i < list.size(); i++) {
            System.out.println(list.get(i));
        }
        Iterator<String> iterator = list.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next());
        }
    }
}

List集合的子类

ArrayList集合
  • java.util.ArrayList集合数据存储的结构是数组结构,元素增删慢,查找快
LinkedList集合
  • java.util.LinkedList集合数据存储的结构是链表结构,方便元素添加、删除的集合,LinkedList是一个双向链表
  • 特点:
  1. 底层是一个链表结构:查询慢,增删快
  2. 里面包含了大量操作首尾元素的方法

注意:使用LinkedList集合特有的方法不能使用多态

  • public void addFirst(E e):将指定元素插入此列表的开头
  • public void addLast(E e):将指定元素添加到此列表的结尾
  • public E getFirst():返回此列表的第一个元素
  • public E getLast():返回此列表的最后一个元素
  • public E removeFirst():移除并返回此列表的第一个元素
  • public E removeLast():移除并返回此列表的最后一个元素
  • public E pop():从此列表所表示的堆栈处弹出一个元素
  • public void push(E e):将元素推入此列表所表示的堆栈
  • public boolean isEmpty():如果列表不包含元素,则返回true
public class Test {
    public static void main(String[] args) {
        LinkedList<String> linked = new LinkedList<>();
        linked.add("a");
        linked.add("b");
        linked.add("c");
        System.out.println(linked);//[a, b, c]
        linked.addFirst("thomas");//[thomas, a, b, c]
        linked.push("thomas");//[thomas, a, b, c]
        System.out.println(linked);
        linked.addLast("hello");
        System.out.println(linked);//[thomas, a, b, c, hello]
        System.out.println(linked.getFirst());//thomas
        System.out.println(linked.getLast());//hello
        System.out.println(linked.removeFirst());//thomas
        System.out.println(linked);//[a, b, c,hello]
        System.out.println(linked.removeLast());//hello
        System.out.println(linked);//[a, b, c]
        String pop = linked.pop();
        System.out.println(pop);//thomas
        System.out.println(linked);//[a, b, c]
        boolean empty = linked.isEmpty();
        System.out.println(empty);//false
    }
}

Vector集合
  • Vector类实现了可扩展的对象数组。 像数组一样,它包含可以使用整数索引访问的组件。 但是, Vector的大小可以根据需要增长或缩小,以适应在创建Vector之后添加和删除项目。

  • 从Java 2平台v1.2,这个类被改造为实现List接口,使其成为成员Java Collections Framework。 与新集合实现不同, Vector是同步的。 如果不需要线程安全的实现,建议使用ArrayList代替Vector

Set集合

  • java.util.Set接口和java.util.List接口一样,同样继承于Collection接口,它与Collection接口中的方法基本一致,并没有对Collection接口进行功能上的扩充,只是比Collection更加严格了。与List接口不同的是,Set接口中的元素无序,并都会以某种规则保证纯如的元素不出现重复

  • Set集合有多个子类,以下介绍其中java.util.HashSetjava.util.LinkedHashSet这两个集合

  • 特点:

    1、不允许存储重复元素

    2、没有索引没有带索引的方法也不能使用普通的for循环遍历

Set集合取出元素的方式可以采用:迭代器、增强for循环

HashSet集合

  • java.util.HashSet集合是Set集合的一个实现类,它所存储的元素是不可重复的,并且元素都是无序的。java.util.HashSet底层的实现其实是一个java.util.HashMap支持

  • HashSet是根据对象的哈希值来确定元素在集合中的存储位置,因此具有良好的存取和查找性能。保证元素唯一性的方式依赖于:hashCodeequals方法

  • 特点:

    1、不允许存储重复元素

    2、没有索引没有带索引的方法也不能使用普通的for循环遍历

    3、是一个无序的集合,存储元素和取出元素的顺序有可能不一致

    4、底层是一个哈希表结构(查询速度非常快)

public class Test {
    public static void main(String[] args) {
        Set<Integer> set = new HashSet<>();
        set.add(1);
        set.add(3);
        set.add(2);
        set.add(1);
        Iterator<Integer> it = set.iterator();
        while (it.hasNext()){
            System.out.println(it.next());//1  2   3
        }
        System.out.println("----------------");
        for (Integer i : set) {
            System.out.println(i);//1  2   3
        }
    }
}

哈希值

  • 哈希值:是一个十进制的整数,由系统随机给出(就是对象的地址值,是一个逻辑地址,是模拟出来得到的地址,不是数据实际存储的物理地址)

在Object类中有一个方法,可以获取对象的哈希值

  • int hashCode() :返回对象的哈希码值

    hashCode方法的源码:

    public native int hashCode();//native:代表该方法调用的是本地操作系统的方法
    
    public class Test {
        public static void main(String[] args) {
            //Person类继承了Object类,所以可以使用Object类的hashCode方法
            Person p = new Person();
            int i = p.hashCode();
            System.out.println(i);//824909230
    
            Person p1 = new Person();
            System.out.println(p1.hashCode());//122883338
            /*
            * toString()源码:
            * public String toString() {
            *     return getClass().getName() + "@" + Integer.toHexString(hashCode());
            * }
            * */
            System.out.println(p);//com.thomas.test.Person@312b1dae
            System.out.println(p1);//com.thomas.test.Person@7530d0a
            /*
            * String类的哈希值
            * String类重写了Object类的hashCode方法
            * */
            String s = new String("abc");
            String s1 = new String("abc");
            System.out.println(s.hashCode());//96354
            System.out.println(s1.hashCode());//96354
    
            System.out.println("重地".hashCode());//1179395
            System.out.println("通话".hashCode());//1179395
        }
    }
    

HashSet集合存储数据的结构(哈希表)

  • 在JDK 1.8之前,哈希表底层采用数组+链表实现,即使用链表处理冲突,同一个hash值的链表都存储在一个链表中,但是当位于一个同种的元素较多,即hash值相等的元素较多时,通过key值依次查找的效率较低,而在JDK 1.8中,哈希表存储采用数组+链表+红黑树实现,当链表长度超过阈值**(8)**的时候,将链表转换为红黑树,这样大大减少了查找时间

在这里插入图片描述

Set集合存储元素不重复的原理

在这里插入图片描述

HashSet存储自定义类型元素

  • 给HashSet中存放自定义类型元素时,需要重写对象中的hashCodeequals方法,建立自己的比较方式,才能保证HashSet集合中的对象唯一
public class Person {

    private String name;
    private int age;

    public Person() {
    }

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

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

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Person person = (Person) o;
        return age == person.age &&
                Objects.equals(name, person.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, age);
    }
}


/*
* HashSet集合存储自定义的元素
* Set集合存储元素唯一,存储的元素(String,Integer,....Student,Person),必须重写hashCode和equals方法
*要求:
*   同名同年龄的人,视为一个人,只能存放一次
* */
public class Test {
    public static void main(String[] args) {

        HashSet<Person> set = new HashSet<>();

        Person p1 = new Person("tom",18);
        Person p2 = new Person("tom",18);
        Person p3 = new Person("tom",20);

        System.out.println(p1.hashCode());//3566785
        System.out.println(p2.hashCode());//3566785
        System.out.println(p1.equals(p2));//true

        set.add(p1);
        set.add(p2);
        set.add(p3);

        System.out.println(set);//[Person{name='tom', age=20}, Person{name='tom', age=18}]

    }
}

LinkedHashSet

  • HashSet保证元素唯一,可是元素存放进去是没有顺序的,在HashSet下面有一个子类java.util.LinkedHashSet,它是一个链表和哈希表组合的一个数据存储结构

  • 特点:

    底层是一个哈希表(数组+链表/红黑树)+链表;多了一条链表 (记录元素的存储顺序),保证元素有序

public class Test {
    public static void main(String[] args) {
        HashSet<String> set = new HashSet<>();
        set.add("ccc");
        set.add("bbb");
        set.add("aaa");
        set.add("bbb");
        System.out.println(set);//[aaa, ccc, bbb]  无序的,不允许重复

        LinkedHashSet<String> linked = new LinkedHashSet<>();
        linked.add("bbb");
        linked.add("ccc");
        linked.add("bbb");
        linked.add("aaa");
        System.out.println(linked);//[bbb, ccc, aaa] 有序的,不允许重复
    }
}

可变参数

  • 可变参数:是JDK 1.5之后出现的新特性

  • 使用前提:当方法的参数列表数据类型已经确定,但是参数的个数不确定时就可以使用可变参数

  • 使用格式:

    修饰符 返回值类型 方法名(数据类型...变量名){	}
    
  • 可变参数的原理:

    可变参数底层就是一个数组,根据传递参数个数不同,会创建不同长度的数组,来存储这些参数

    传递的参数个数可以时0个,1个也可以是多个

  • 注意事项:

    一个方法的参数列表,只能有一个可变参数

    如果方法的参数有多个,那么可变参数必须写在参数列表的末尾

  • 可变参数的特殊(终结)写法

    修饰符 返回值类型 方法名(Object...obj){	}
    
public class Test {
    public static void main(String[] args) {
        int result = add(10, 20, 30, 50);//110
        System.out.println(result);
        int result1 = add(10, 20);//30
        System.out.println(result1);
    }
    /*
    * 定义计算(0-n)个整数和的方法
    * 已知:计算整数的和,数据类型已经确定int
    * 但是参数个数不确定,使用可变参数处理
    * add();创建一个长度为0的数组 new int[0];
    * add(10);创建一个长度为1的数组 new int[]{10};
    * add(10,20);创建一个长度为2的数组 new int[]{10,20};
    * ........
    * */
    private static int add(int...arr) {
        // System.out.println(arr);//[I@27973e9b 底层是一个数组
        // System.out.println(arr.length);//0
        int sum = 0;
        for (int i : arr) {
            sum += i;
        }
        return sum;
    }
}

Collections

java.util.Collections集合工具类,用来对集合进行操作

常用功能

  • public static <T> boolean addAll(Collection<T> c,T... elements) :往集合中添加一些元素
  • public static void shuffle(List<?> list):打乱集合顺序
  • public static <T> void sort(List<T> list):将集合中元素按照默认规则排序
  • public static <T> void sort(List<T> list,Comparator<? super T>):将集合中元素按照指定规则排序
public class Test {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        Collections.addAll(list,"a","b","c","d","e");
        System.out.println(list);//[a, b, c, d, e]
        Collections.shuffle(list);
        System.out.println(list);//[d, a, e, c, b]
    }
}
public class Person implements Comparable<Person>{

    private String name;
    private int age;

    public Person() {
    }

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

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

    @Override
    public int compareTo(Person o) {
        //(this,参数)
        return this.getAge() - o.getAge();//根据年龄升序
        // return o.getAge() - this.getAge();//根据年龄降序
    }
}

/*
* `public static <T> void sort(List<T> list)`:将集合中元素按照默认规则排序
*  注意:
*     sort(List<T> list)使用前提:
*        被排序的集合中存储的元素,必须实现Comparable接口,重写接口中的compareTo方法定义排序规则
*        Integer,String都实现了Comparable接口,
*        自定义的类对象的集合使用sort排序,类对象必须实现Comparable接口,重写接口的compareTo方法定义排序规则
* */
public class Test {
    public static void main(String[] args) {
        ArrayList<Integer> list01 = new ArrayList<>();
        list01.add(1);
        list01.add(3);
        list01.add(2);
        System.out.println(list01);//[1, 3, 2]
        Collections.sort(list01);
        System.out.println(list01);//[1, 2, 3]
        ArrayList<String> list02 = new ArrayList<>();
        list02.add("a");
        list02.add("c");
        list02.add("b");
        System.out.println(list02);//[a, c, b]
        Collections.sort(list02);
        System.out.println(list02);//[a, c, b]
        ArrayList<Person> list03 = new ArrayList<>();
        list03.add(new Person("张三",20));
        list03.add(new Person("李四",18));
        list03.add(new Person("王五",22));
        System.out.println(list03);//[Person{name='张三', age=20}, Person{name='李四', age=18}, Person{name='王五', age=22}]
        Collections.sort(list03);
        System.out.println(list03);//[Person{name='李四', age=18}, Person{name='张三', age=20}, Person{name='王五', age=22}]
    }
}
/*
* `public static <T> void sort(List<T> list,Comparator<? super T>)`:将集合中元素按照指定规则排序
*  Comparator和Comparable的区别:
*      Comparable:自己(this)和别人(参数)比较,自己需要实现Comparable接口重写比较规则的compareTo方法
*      Comparator:相当于找一个第三方裁判进行比较
* */
public class Test {
    public static void main(String[] args) {
        ArrayList<Integer> list01 = new ArrayList<>();
        list01.add(3);
        list01.add(1);
        list01.add(2);
        System.out.println(list01);//[3, 1, 2]
        Collections.sort(list01, new Comparator<Integer>() {
            //定义排序规则
            @Override
            public int compare(Integer o1, Integer o2) {
                return o1 - o2;//升序
                //return o2 - o1;//降序
            }
        });
        System.out.println(list01);//[1, 2, 3]

        ArrayList<Person> list02 = new ArrayList<>();
        list02.add(new Person("a张三",18));
        list02.add(new Person("李四",23));
        list02.add(new Person("王五",20));
        list02.add(new Person("b张三",18));
        System.out.println(list02);//[Person{name='a张三', age=18}, Person{name='李四', age=23}, Person{name='王五', age=20}, Person{name='b张三', age=18}]
        Collections.sort(list02, new Comparator<Person>() {
            @Override
            public int compare(Person o1, Person o2) {
                //按照年龄升序
                int result = o1.getAge() - o2.getAge();
                //如果两个人年龄相同,使用姓名的第一个字母比较
                if (result == 0){
                    result = o1.getName().charAt(0) - o2.getName().charAt(0);
                }
                return result;
            }
        });
        System.out.println(list02);//[Person{name='a张三', age=18}, Person{name='b张三', age=18}, Person{name='王五', age=20}, Person{name='李四', age=23}]
    }
}

Map集合

  • Collection中的集合,元素是孤立存在的,向集合中存储元素采用一个个元素的方式存储
  • Map中的集合,元素是成对存在的,每个元素有键与值两部分组成,通过键可以找到对应的值
  • Collection中的集合被称为单列集合,Map中的集合被称为双列集合
  • 需要注意的是,Map中的集合不能包含重复的键,值可以重复,每个键只能对应一个值

java.util.Map<K,V>集合

特点:

  1. Map集合是一个双列集合,一个元素包含两个值(一个key,一个value)
  2. Map集合中的元素,key和value的数据类型可以相同,也可以不同
  3. Map集合中的元素,key是不允许重复的,value是可以重复的
  4. Map集合中的元素,key和value是一一对应的

Map集合的常用子类

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

    java.util.HashMap<K,V>集合 implements Map<K,V>接口

    特点:

    1、HashMap集合底层是哈希表:查询速度特别快

    ​ JDK 1.8之前使用的是数组+单向链表

    ​ JDK 1.8之后使用的是数组+单向链表/红黑树(链表长度超过8),提高查询速度

    2、HashMap集合是一个无序的集合,存储元素和取出全速的顺序可能不一致

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

    java.util.LinkdeHashMap<K,V>集合extends HashMap<K,V>集合

    特点:

    1、LinkdeHashMap集合的底层是哈希表+链表(保证迭代的顺序)

    2、LinkdeHashMap集合是一个有序的集合,存储和取出元素的顺序是一致的

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

Map接口中的常用方法

  • public V put(K key,V value):把指定的键与指定的值添加到Map集合中
  • public V remove(Object key):把指定的键所对应的键值对元素在Map中删除,返回被删除的元素
  • boolean containsKey(Object key):判断集合中是否包含指定的键
  • public V get(Object key):根据指定的键,在Map集合中获取对应的值
  • public Set<K> keySet():获取Map集合中的所有键,存储到Set集合中
  • public Set<Map.Entry<K,V>> entrySet():获取到Map集合中所有的键值对对象的集合
public class Test {
    public static void main(String[] args) {
        //show01();
        //show02();
        //show03();
    }
    /*
    * `public V get(Object key)`:根据指定的键,在Map集合中获取对应的值
    * 返回值 V:key存在,返回对应的value,key存在返回null
    * `boolean containsKey(Object key)`:判断集合中是否包含指定的键
    * 存在返回true不存在返回false
   * */
    private static void show03() {
        Map<String,Integer> map = new HashMap<>();
        map.put("1",555);
        map.put("2",666);
        map.put("3",777);
        Integer i = map.get("3");
        System.out.println(i);//777
        System.out.println(map.get("5"));//null
        System.out.println(map.containsKey("3"));//true
        System.out.println(map.containsKey("5"));//false
    }

    /*
    * `public V remove(Object key)`:把指定的键所对应的键值对元素在Map中删除,返回被删除的元素
    * 返回值 V:key存在,v是被删除的值,key不存在,v的值为null
    * */
    private static void show02() {
        Map<String, Integer> map = new HashMap<>();
        map.put("1",111);
        map.put("2",222);
        map.put("3",333);
        System.out.println(map);//{1=111, 2=222, 3=333}
        Integer i = map.remove("1");
        System.out.println(i);//111
        System.out.println(map);//{2=222, 3=333}
        Integer i1 = map.remove("4");
        System.out.println(i1);//null
    }

    /*
    *`public V put(K key,V value)`:把指定的键与指定的值添加到Map集合中
    * 返回值 V:存储键值对的时候,key不重复,返回值为null
    *         存储键值对的时候,key重复,会使用新的value替换map中重复的value,返回被替换的value值
    * */
    private static void show01() {
        Map<String, String> map = new HashMap<>();
        // String v1 = map.put("第一个", "abc");
        // System.out.println(v1);//null
        // String v2 = map.put("第一个", "cde");
        // System.out.println(v2);//abc
        // System.out.println(map);//{第一个=cde}
        map.put("1","001");
        map.put("2","002");
        map.put("3","003");
        System.out.println(map);//{1=001, 2=002, 3=003}
    }
}

Map集合遍历键找值方法

  • 键找值方法:通过元素中的键,获取键所对应的值

  • 步骤:

    1、获取Map中所有的键,由于键是唯一的,所以返回一个Set集合存储所有的键(keySet()

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

    3、根据键,获取所对应的值(get(K key)

/*
`public Set<K> keySet()`:获取Map集合中的所有键,存储到Set集合中
*/ 
Map<String,Integer> map = new HashMap<>();
        map.put("1",555);
        map.put("2",666);
        map.put("3",777);
        Set<String> keys = map.keySet();
        for (String key : keys) {
            Integer value = map.get(key);
            System.out.println("key: " + key + " = value:" + value);
            //key: 1 = value:555 key: 2 = value:666 key: 3 = value:777
        }
        System.out.println("-----------------");
        Iterator<String> it = keys.iterator();
        while (it.hasNext()){
            String key = it.next();
            Integer value = map.get(key);
            System.out.println("key: " + key + " = value:" + value);
            //key: 1 = value:555 key: 2 = value:666 key: 3 = value:777
        }

Entry键值对对象

  • Map中存放的是两个对象,一个是key(键),一个是value(值),它们在Map中是一一对应的关系,这一对对象又称Map中的一个Entry(项)Entry将键值对的对应关系封装成了对象,即键值对对象,这样我们在遍历Map集合的时候,就可以从每一个键值对对象(Entry)中获取对应的键与对应的值
  • public K getKey():获取Entry对象中的键
  • public V getValue():获取Entry对象中的值
  • 在Map集合中也提供了获取所有Entry对象的方法:
    • public Set<Map.Entry<K,V>> entrySet():获取到Map集合中所有的键值对对象的集合
/*
Map集合遍历的第二种方式:使用Entry对象遍历
*/
public class Test {
    public static void main(String[] args) {
        show01();
    }
    /*
    *  `public Set<Map.Entry<K,V>> entrySet()`:获取到Map集合中所有的键值对对象的集合
    *   Map.Entry<K,V>:在Map接口中有一个内部接口Entry
    *   作用:当Map集合一创建,那么会在Map集合中创建一个Entry对象,用来记录键与值
    *  * */
    private static void show01() {
        Map<String,Integer> map = new HashMap<>();
        map.put("1",555);
        map.put("2",666);
        map.put("3",777);
        Set<Map.Entry<String, Integer>> entrySet = map.entrySet();
        for (Map.Entry<String, Integer> entry : entrySet) {
            String key = entry.getKey();
            Integer value = entry.getValue();
            System.out.println("key: " + key + " = value:" + value);
            //key: 1 = value:555 key: 2 = value:666 key: 3 = value:777
            //System.out.println(entry);//1=555,2=666,3=777
        }
        System.out.println("---------------------");
        Iterator<Map.Entry<String, Integer>> it = entrySet.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);
            //key: 1 = value:555 key: 2 = value:666 key: 3 = value:777
        }
    }
}    

HashMap存储自定义类型键值对

  • Map集合保证key是唯一的:作为key元素,必须重写hashCode方法和equals方法,以保证key唯一
public class Person {

    private String name;
    private int age;

    public Person() {
    }

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

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

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Person person = (Person) o;
        return age == person.age &&
                Objects.equals(name, person.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, age);
    }
}

public class Test {
    public static void main(String[] args) {
        //show01();
        show02();
    }

    /*
    * key:Person类型
    *     Person类型必须重写hashCode和equals方法以保证key唯一
    * value:String类型
    *     可以重复
    * */
    private static void show02() {
        HashMap<Person,String> map = new HashMap<>();
        map.put(new Person("女王",18),"英国");
        map.put(new Person("普京",30),"俄罗斯");
        map.put(new Person("奥巴马",31),"美国");
        map.put(new Person("女王",18),"毛里求斯");
        Set<Map.Entry<Person, String>> entrySet = map.entrySet();
        for (Map.Entry<Person, String> entry : entrySet) {
            System.out.println(entry.getKey()+"---->"+entry.getValue());
            //Person{name='奥巴马', age=31}---->美国
            // Person{name='女王', age=18}---->毛里求斯
            // Person{name='普京', age=30}---->俄罗斯
        }
    }

    /*
    * key:String类型
    *     String类型重写了hashCode和equals方法,保证key唯一
    * value:Person
    *     value可以重复(同名同年龄的视为一个人)
    * */
    private static void show01() {
        HashMap<String,Person> map = new HashMap<>();
        map.put("北京",new Person("张三",18));
        map.put("上海",new Person("李四",20));
        map.put("西安",new Person("王五",19));
        map.put("北京",new Person("赵六",18));
        Set<String> set = map.keySet();
        for (String key : set) {
            System.out.println(key+"--->"+map.get(key));
        }

    }
}

LinkedHashMap

  • HashMap保证元素唯一,并且查询速度很快,可是成对元素存放进去是没有顺序的,我们可以通过LinkedHashMap去解决
  • HashMap下面有一个子类LinkedHashMap,它是链表和哈希表组合的一个数据存储结构,记录元素的顺序
public class Test {
    public static void main(String[] args) {
        HashMap<String, String> map = new HashMap<>();
        map.put("1","aaa");
        map.put("3","ccc");
        map.put("2","bbb");
        map.put("1","aaa");
        Set<Map.Entry<String, String>> entrySet = map.entrySet();
        for (Map.Entry<String, String> entry : entrySet) {
            System.out.println(entry.getKey() + "--->" + entry.getValue());
            //1--->aaa
            //2--->bbb   key不允许重复,无序
            //3--->ccc
        }

        System.out.println("---------------------");

        LinkedHashMap<String, String> linked = new LinkedHashMap<>();
        linked.put("1","aaa");
        linked.put("3","ccc");
        linked.put("2","bbb");
        linked.put("1","aaa");
        Set<Map.Entry<String, String>> entrySet1 = linked.entrySet();
        for (Map.Entry<String, String> entry1 : entrySet1) {
            System.out.println(entry1.getKey() + "--->" + entry1.getValue());
            //1--->aaa
            //3--->ccc key不允许重复,有序
            //2--->bbb
        }
    }
}

Hashtable集合

  • java.util.Hashtable<K,V>结合实现了Map<K,V>接口

  • Hashtable:

    1、底层也是一个哈希表,是一个线程安全的集合,是单线程集合,速度慢

    2、Hashtable不能存储null值和null键

  • HashMap:

    1、底层是一个哈希表,是一个线程不安全的集合,是多线程的集合,速度快

    2、HashMap可以存储null值和null键

  • HashtableVector集合一样,在JDK 1.2版本之后被更先进的集合(HashMap,ArrayList)取代了

  • Hashtable的子类Properties依然在使用,Properties集合是唯一一个和IO流结合的集合

public class Test {
    public static void main(String[] args) {
        HashMap<String, String> map = new HashMap<>();
        map.put(null,"a");
        map.put("a",null);
        map.put(null,null);
        System.out.println(map);//{null=null, a=null}

        System.out.println("----------------------");

        Hashtable<String, String> table = new Hashtable<>();
        table.put(null,"a");//NullPointerException
        table.put("a",null);//NullPointerException
        table.put(null,null);//NullPointerException
        System.out.println(table);
    }
}

JDK9对集合添加的优化

  • JDK 9的新特性:

    1、List接口、Set接口、Map接口,里面添加了一个静态方法of,可以给集合一次性添加多个元素

    2、static <E> List<E> of (E... elements)

    3、使用前提:当即和中存储的元素的个数已经确定了,不再改变时

  • 注意:

    1、of方法只适用于List接口、Set接口、Map接口,不适用于接口的实现类

    2、of方法的返回值是一个不能改变的集合,集合不能再使用add、put方法添加元素,会抛出异常

    3、Set接口和Map接口在调用of方法的时候,不能有重复的元素,否则会抛出异常

public class Test {
    public static void main(String[] args) {
        List<String> list = List.of("a", "b", "a", "c", "d");
        System.out.println(list);//[a, b, a, c, d]
        //list.add("x");//UnsupportedOperationException不支持操作异常


        //IllegalArgumentException: duplicate element: a
        //非法参数异常,有重复元素a
        //Set<String> set = Set.of("a", "b", "a", "c", "d");
        Set<String> set = Set.of("a", "b", "c", "d");
        System.out.println(set);//[a, d, c, b]
        //set.add("x");//UnsupportedOperationException不支持操作异常


        //IllegalArgumentException: duplicate key: 张三
        //非法参数异常,有重复的键张三
        //Map<String, Integer> map = Map.of("张三", 18, "李四", 19, "王五", 20, "张三", 19);
        Map<String, Integer> map = Map.of("张三", 18, "李四", 19, "王五", 20);
        System.out.println(map);//{王五=20, 李四=19, 张三=18}
        //map.put("赵六",25);//UnsupportedOperationException不支持操作异常
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

掉发阿龙

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值