Java集合框架(二)

泛型

泛型,即“参数化类型”。一提到参数,最熟悉的就是定义方法时有形参,然后调用此方法时传递实参。那么参数化类型怎么理解呢?

顾名思义,就是将类型由原来的具体的类型参数化,类似于方法中的变量参数,此时类型也定义成参数形式(可以称之为类型形参),然后在使用/调用时传入具体的类型(类型实参)。

泛型的本质是为了参数化类型(在不创建新的类型的情况下,通过泛型指定的不同类型来控制形参具体限制的类型)。也就是说在泛型使用过程中,操作的数据类型被指定为一个参数,这种参数类型可以用在类、接口和方法中,分别被称为泛型类、泛型接口、泛型方法

泛型类

语法:

class 类名称 <泛型标识:T、K、E、V等>{
    泛型标识 变量名;
}

【演示】

package com.gather.generics;

public class GenericsDemo01<T> {
    private T name;// name变量的类型是T类型

    public GenericsDemo01(T name) {// 泛型类的构造方法(泛型作为方法的参数)
        this.name = name;
    }

    public T showName() {// 泛型作为方法的返回值
        return this.name;
    }
}
package com.gather.generics;

public class Test01 {
    public static void main(String[] args) {
        GenericsDemo01<String> s1 = new GenericsDemo01<String>("张三");
        String str = s1.showName();
        System.out.println(str);
        GenericsDemo01<Integer> s2 = new GenericsDemo01<Integer>(1234);
        Integer ite = s2.showName();
        System.out.println(ite);
    }
}
执行结果:
张三
1234

注意:1. 泛型只能使用引用类型

  2. 不用泛型类型对象之间不能相互赋值

泛型方法

泛型类:是在实例化类的时候指明泛型的具体类型;

泛型方法:是在调用方法的时候指明泛型的具体类型

泛型方法定义规则:

  • 所有泛型方法声明都有一个类型参数声明部分(由尖括号分隔),该类型参数声明部分在方法返回类型之前。
  • 每一个类型参数声明部分包含一个或多个类型参数,参数间用逗号隔开。一个泛型参数,也被称为一个类型变量,是用于指定一个泛型类型名称的标识符。
  • 类型参数能被用来声明返回值类型,并且能作为泛型方法得到的实际参数类型的占位符。
  • 泛型方法体的声明和其他方法一样。注意类型参数只能代表引用型类型,不能是原始类型(像int,double,char的等)。

【演示】

package com.gather.generics;

public class GnericsDemo02 {
    // 无返回值的泛型方法
    public static <T> void print(T input) {
        System.out.println(input);
    }
    // 有返回值的泛型方法
    public static <T> boolean compare(T a, T b) {
        if (a.equals(b)) {
            return true;
        }
        return false;
    }

    public static void main(String[] args) {
        // 创建不同类型的对象
        Integer i = new Integer(1);
        Integer j = new Integer(8);
        Character c = new Character('A');
        String str = "java";
        print(i);
        print(c);
        print(str);
        System.out.println(compare(i, j));
    }
}
执行结果:
1
A
java
false

泛型接口

语法:

interface 接口名 <泛型标识:T、K、E、V等> {
    泛型标识 变量名;
}

【演示】

package com.gather.generics;

public interface GenericsDemo03<T> {
    String name = "张三";

    T show(T t);

    void print(T t);
}

该接口有两种实现类有以下两种表示方法

【第一种:在实现类中确定泛型】

public class GenericsRealize1 implements GenericsDemo03 <String>{
    @Override
    public String show(String s) {
        if (s.equals("java")) {
            return "yes";
        }
        return "No";
    }

    @Override
    public void print(String s) {
        System.out.println(s);
    }
}
public class Test02 {
    public static void main(String[] args) {
        GenericsRealize1 g = new GenericsRealize1();
        String str1 = g.show("java");
        String str2 = g.show("python");
        System.out.println(str1);
        System.out.println(str2);
        g.print("hello");
    }
}
执行结果:
yes
No
hello

【第二种:在实现类中不确定泛型,使用泛型实现类】

package com.gather.generics;

public class GenericsRealize2<T> implements GenericsDemo03<T> {
    @Override
    public T show(T t) {
        if (t.equals("java")) {
            System.out.println("hahahaha");
        }
        return t;
    }

    @Override
    public void print(T t) {
        System.out.println(t);
    }
}
public class Test03 {
    public static void main(String[] args) {
        GenericsRealize2<Integer> g1 = new GenericsRealize2<Integer>();
        System.out.println(g1.show(123));
        g1.print(100);
        GenericsRealize2<String> g2 = new GenericsRealize2<String>();
        System.out.println(g2.show("java"));
        g2.print("张三");
        new GenericsRealize2<Character>().print('A');
        new GenericsRealize2<Double>().print(3.14);
    }
}
执行结果:
123
100
hahahaha
java
张三
A
3.14

泛型集合

概念:参数化类型、类型安全的集合,强制集合元素的类型必须一致

特点:

  • 编译时即可检查,而非运行时抛出异常
  • 访问时,不必类型转换(拆箱)
  • 不同泛型之间不能相互赋值,泛型不存在多态
package com.gather.generics;

import java.util.ArrayList;

public class Demo {
    public static void main(String[] args) {
        ArrayList<String> arrayList = new ArrayList<String>();
        //ArrayList arrayList = new ArrayList();其类型是Object类
        arrayList.add("张三");
        arrayList.add("王五");
        arrayList.add(0, "李四");
        // arrayList.add(123);123不是String类型,报错
        for (String s : arrayList) {
            System.out.println(s);
        }
    }
}
执行结果:
李四
张三
王五

Set接口

特点:无序、无下标、元素不可重复

方法:全部继承自Collection中的方法,增、删、遍历、判断与collection一致

【演示】

package com.gather.set;

import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

public class Demo01 {
    public static void main(String[] args) {
        Set<String> set = new HashSet<String>();// 实例化集合,Set是接口必须利用其实现类创建对象
        set.add("张三");// 添加元素
        set.add("李四");
        set.add("王五");
        set.add("赵六");
        //set.add(0, "赵六");不能通过下标添加元素(Set无下标)
        //set.add("王五");不能添加相同的元素
        System.out.println(set.size());
        System.out.println(set.toString());// 元素是无序的
        set.remove("张三");// 删除元素
        System.out.println(set.contains("李四"));// 判断集合中是否包含"李四"
        System.out.println(set.isEmpty());// 判断集合是否为空
        /*
        遍历元素:1.利用增强for;2.利用迭代器Iterator
         */
        for (String str : set) {
            System.out.println(str);
        }
        Iterator<String> it = set.iterator();
        while (it.hasNext()) {
            System.out.println(it.next());
        }
    }
}
执行结果:
4
[李四, 张三, 王五, 赵六]
true
false
李四
王五
赵六
李四
王五
赵六

HashSet 类

存储结构:哈希表(数组+链表\红黑树)

数组结构:把元素进行了分组(相同哈希值的元素是一组)

链表/红黑树结构:把相同哈希值的元素连到一起(如果链表的长度超过了8位,那么就会把链转换位红黑树(提高查询的速度))

存储过程:(重复依据)

  1. 先根据hashCode计算保存的位置(数组位置),如果位置为空,直接保存,若不为空,进行第二步
  2. 再执行equals方法,如果equals为true,则认为是重复,重复的元素不会被添加,若为false则形成链表

基于hashCode计算元素存放位置,当存入元素的哈希码相同时,会调用equals进行确认,如果结果为true,则拒绝后者存入

重写hashCode方法时31的利用

  • 利用31这个质数,减少散列冲突
  • 31提高执行效率 31 * i = (i << 5) - i 转为移位操作

【演示】

package com.gather.hashset;

public class Student {
    private String name;
    private int age;

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

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o == null) {
            return false;
        }
        if (o.getClass() != this.getClass()) {
            return false;
        }
        if (o instanceof Student) {
            Student student = (Student) o;
            if (this.name.equals(student.name) && this.age == student.age) {
                return true;
            }
        }
        return false;
    }

    @Override
    public int hashCode() {
        int result = name.hashCode();
        result = 31 * result + age;
        return result;
    }

    @Override
    public String toString() {
        return "{" + this.name + "," + this.age + "}";
    }
}
package com.gather.hashset;

import java.util.HashSet;
import java.util.Iterator;

public class Demo {
    public static void main(String[] args) {
        Student s1 = new Student("张三", 10);
        Student s2 = new Student("李四", 10);
        Student s3 = new Student("王五", 10);
        Student s4 = new Student("赵六", 10);
        HashSet<Student> hashset = new HashSet<Student>();
        hashset.add(s1);
        hashset.add(s2);
        hashset.add(s3);
        hashset.add(s4);
        //hashset.add(s1);重复的元素不会被添加
        //hashset.add(new Student("张三", 10));若Student类中未重写hashCode和equals方法,则会添加成功
        hashset.remove(new Student("李四", 10));// 等价于hashset.remove(s2);(Student类中重写了hashCode和equals方法)
        System.out.println(hashset.size());
        System.out.println(hashset.contains(new Student("赵六", 10)));//等价于hashset.contains(s4);(Student类中重写了hashCode和equals方法)
        /*
        遍历元素:1.利用增强for; 2.利用迭代器Iterator
         */
        for (Student s : hashset) {
            System.out.println(s);
        }
        Iterator<Student> it = hashset.iterator();
        while (it.hasNext()) {
            System.out.println(it.next());
        }
        System.out.println(hashset.toString());
        hashset.clear();// 清空集合
        System.out.println(hashset.isEmpty());
    }
}
执行结果:
3
true
{王五,10}
{赵六,10}
{张三,10}
{王五,10}
{赵六,10}
{张三,10}
[{王五,10}, {赵六,10}, {张三,10}]
true

TreeSet类

TreeSet和HashSet的区别在于, HashSet不可以进行排序,TreeSet可以进行排序, 默认使用字典顺序排序, 也可以进行自定义排序。

TreeSet两种排序方式:

  • 让自定义的类实现Comparable 接口

    • 1.Student类中实现 Comparable< T >接口

      2.重写Comparable接口中的CompareTo方法

  • 创建一个比较类,并让其实现Comparator接口

    • 1.构造一个新的空 TreeSet,它根据指定比较器进行排序

      2.重写Comparator接口中的Compare方法

存储结构:红黑树

特点:

  • 基于排列顺序实现元素不重复
  • 实现SortedSet接口,对集合元素自动排序
  • 元素对象的类型必须实现Comparable接口,指定排序规则
  • 通过CompareTo方法确定是否为重复元素

注:其中元素对象的类型必须实现Comparable接口有两种方式。第一种是在一个实现类中实现Comparable接口,在该类中重写CompareTo方法;第二种是在创建TreeSet集合时就指定比较规则,使用匿名内部类

自定义的类实现Comparable 接口

【演示】

public class Person implements Comparable<Person> {
    private String name;
    private int age;

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

    @Override
    public String toString() {
        return "{" + this.name + "," + this.age + "}";
    }

    @Override
    public int compareTo(Person o) {
        int a = this.name.compareTo(o.name);// 若a等于0,则说明name相同
        int b = this.age - o.age;// 若b等于0,则说明age相同
        return a == 0 ? b : a;// 如果a等于0,就返回b的值,否则返回a的值(先对名字进行排序,再对年龄进行排序)
    }
}
package com.gather.treeset;

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

public class Demo01 {
    public static void main(String[] args) {
        TreeSet<Person> p = new TreeSet();
        Person p1 = new Person("afang", 5);
        Person p2 = new Person("afang", 8);// p1和p2的name相同,比较age
        Person p3 = new Person("xiaoming", 3);
        Person p4 = new Person("zhangsan", 8);
        Person p5 = new Person("xy", 5);
        p.add(p1);// 添加元素
        p.add(p2);
        p.add(p3);
        p.add(p4);
        p.add(p5);
        //p.add(new Person("xy",5));无法添加重复的元素
        System.out.println("元素个数:" + p.size());
        System.out.println(p.toString());
        p.remove(new Person("xy", 5));// 删除元素(实体中重写了compareTo方法)等同p.remove(p5)
        System.out.println(p.contains(new Person("zhangsan", 8)));// 判断是否包含(实体中重写了compareTo方法)等同p.contains(p4)
        /*
        元素遍历:1.增强for
        2.迭代器Iterator
         */
        System.out.println("-----for-----");
        for (Person person : p) {
            System.out.println(person);
        }
        System.out.println("-----Iterator-----");
        Iterator<Person> it = p.iterator();
        while (it.hasNext()) {
            System.out.println(it.next());
        }
    }
}
执行结果:
元素个数:5
[{afang,5}, {afang,8}, {xiaoming,3}, {xy,5}, {zhangsan,8}]
true
-----for-----
{afang,5}
{afang,8}
{xiaoming,3}
{zhangsan,8}
-----Iterator-----
{afang,5}
{afang,8}
{xiaoming,3}
{zhangsan,8}

创建一个比较类,并让其实现Comparator接口

【演示】

public class Student {
    private String name;
    private int age;

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

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

    @Override
    public String toString() {
        return "{" + this.name + "," + this.age + "}";
    }
}
package com.gather.treeset;

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

public class Demo02 {
    public static void main(String[] args) {
        TreeSet<Student> t = new TreeSet<>(new Comparator<Student>() {
            @Override
            public int compare(Student o1, Student o2) {
                int x = o1.getName().length() - o2.getName().length();// 若x等于0,则说明o1、o2的name长度一样
                int y = o1.getAge() - o2.getAge();// 若y等于0,则说明o1、o2的age相等
                return x == 0 ? y : x;// 如果x等于0,就返回y的值,否则返回x的值(先对名字长度排序,再对年龄进行排序)
            }
        });
        Student s1 = new Student("张三", 3);
        Student s2 = new Student("王五", 4);
        Student s3 = new Student("刘德华", 25);
        Student s4 = new Student("梁朝伟", 25);
        Student s5 = new Student("欧阳娜娜", 18);
        t.add(s1);
        t.add(s2);// s1和s2的name长度相同,按age大小排序
        t.add(s3);
        t.add(s4);// s3和s4的name长度相同,age相等,所以s4会被认为是重复的元素,不能添加
        t.add(s5);
        System.out.println("元素个数:"+t.size());
        System.out.println(t.toString());
        t.remove(new Student("王五", 4));// 删除元素(重写了compare方法)等同t.remove(s2)
        System.out.println(t.contains(new Student("欧阳娜娜", 18)));// 判断是否包含(重写了compare方法)等同t.contains(s5)
        /*
        元素遍历:1.增强for
        2.迭代器Iterator
         */
        System.out.println("-----for-----");
        for (Student student : t) {
            System.out.println(student);
        }
        System.out.println("-----Iterator-----");
        Iterator<Student> it = t.iterator();
        while (it.hasNext()) {
            System.out.println(it.next());
        }
    }
}
执行结果:
元素个数:4
[{张三,3}, {王五,4}, {刘德华,25}, {欧阳娜娜,18}]
true
-----for-----
{张三,3}
{刘德华,25}
{欧阳娜娜,18}
-----Iterator-----
{张三,3}
{刘德华,25}
{欧阳娜娜,18}

Map接口

Map接口的特点

  1. 用于存储任意键值对(key , value)
  2. 键:无序、无下标、不允许重复(唯一)
  3. 值:无序、无下标、允许重复
方法 描述
V put(K key, V value) 将指定的值与该映射中的指定键相关联(可选操作)
V remove(Object key) 如果存在(从可选的操作),从该地图中删除一个键的映射
default boolean replace(K key, V oldValue,V newValue) 仅当当前映射到指定的值时,才能替换指定键的条目
boolean containsKey(Object key) 如果此映射包含指定键的映射,则返回 true
boolean containsValue(Object value) 如果此地图将一个或多个键映射到指定的值,则返回 true
V get(Object key) 返回到指定键所映射的值
Set< K > keySet() 返回此地图中包含的键的Set视图
Set<Map.Entry<K,V>> entrySet() 返回此地图中包含的映射的Set视图

Map.Entry<K,V>接口

方法 描述
K getKey() 返回与此条目相对应的键
V getValue() 返回与此条目相对应的值

【演示】

package com.gather.map;

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

public class Demo01 {
    public static void main(String[] args) {
        Map<Integer, String> map = new HashMap<Integer, String>();// 通过其实现类创建Map集合
        map.put(1, "中国");// 添加元素
        map.put(2, "美国");
        map.put(3, "英国");
        map.put(4, "法国");
        map.put(2, "俄罗斯");// 添加相同键的元素,原有值将被替换(美国会被俄罗斯替换)
        System.out.println("元素的个数为:" + map.size());
        System.out.println(map.toString());
        map.replace(4, "法国", "日本");// 替换键为4的值为"日本"
        map.remove(3);// 删除键为3的元素
        System.out.println("删除后:" + map.toString());
        System.out.println(map.containsKey(1));// 判断是否包含键为1的元素
        map.containsValue("中国");// 判断是否包含值为"中国"的元素
        /*
        Map集合的遍历:1.keySet() 2.entrySet()
         */
        System.out.println("-------keySet()-------");
        Set<Integer> keyset = map.keySet();// map.keySet()返回的是键的Set集合,即可以用Set集合的遍历方法
        for (Integer key : keyset) {
            System.out.println(key + "=" + map.get(key));// 其值通过map.get(key)获取
        }
        System.out.println("-------entrySet()-------");
        Set<Map.Entry<Integer, String>> entries = map.entrySet();// map.entrySet()的返回的是映射(包含键值)的Set集合(entry映射对)
        for (Map.Entry<Integer, String> entry : entries) {
            System.out.println(entry.getKey() + "=" + entry.getValue());
        }
    }
}
执行结果:
元素的个数为:4
{1=中国, 2=俄罗斯, 3=英国, 4=法国}
删除后:{1=中国, 2=俄罗斯, 4=日本}
true
-------keySet()-------
1=中国
2=俄罗斯
4=日本
-------EntrySet()-------
1=中国
2=俄罗斯
4=日本

HashMap 类

HashMap 实现了 Map 接口,根据键的 HashCode 值存储数据,具有很快的访问速度。HashMap 是无序的,即不会记录插入的顺序。

存储结构:哈希表(数组+链表+红黑树)

【演示】

public class Student {
    private String name;
    private int stuNum;

    public Student(String name, int stuNum) {
        this.name = name;
        this.stuNum = stuNum;
    }

    public String getName() {
        return name;
    }

    public int getStuNum() {
        return stuNum;
    }

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

        Student student = (Student) o;

        if (getStuNum() != student.getStuNum()) return false;
        return getName().equals(student.getName());
    }

    @Override
    public int hashCode() {
        int result = getName().hashCode();
        result = 31 * result + getStuNum();
        return result;
    }

    @Override
    public String toString() {
        return "[" + this.name + "," + this.stuNum + "]";
    }
}
package com.gather.hashmap;

import java.util.HashMap;
import java.util.Map;

public class Demo01 {
    public static void main(String[] args) {
        HashMap<Student, String> students = new HashMap<Student, String>();// 创建集合
        Student s1 = new Student("张三", 1001);
        Student s2 = new Student("李四", 1002);
        Student s3 = new Student("王五", 1003);
        Student s4 = new Student("赵六", 1004);
        students.put(s1, "3班");// 添加元素
        students.put(s2, "3班");// 键不能重复,值可以重复
        students.put(s3, "4班");
        students.put(s4, "5班");
        /*
        students.put(new Student("赵六", 1004), "3班");
        这对键值能够添加成功,但是其键相同,不满足HashMap的特点,
        所以需在Student类重写equals和hashCode方法,避免键相同的重复添加
         */
        students.put(new Student("赵六", 1004), "3班");// 重写equals和hashCode方法后,元素不会重复添加,但是其值会被替换("5班"被替换为"3班")
        System.out.println("元素个数为:" + students.size());
        System.out.println(students.toString());
        System.out.println(students.containsKey(new Student("王五", 1003)));// 若Student类未重写equals和hashCode方法,则返回false
        // 遍历1:keySet()
        System.out.println("-------keySet()-------");
        for (Student s : students.keySet()) {
            System.out.println(s + "=" + students.get(s));
        }
        // 遍历2:entrySet()
        System.out.println("-------entrySet()-------");
        for (Map.Entry<Student, String> entry : students.entrySet()) {
            System.out.println(entry.getKey() + "=" + entry.getValue());
        }
    }
}
执行结果:
元素个数为:4
{[李四,1002]=3班, [赵六,1004]=3班, [王五,1003]=4班, [张三,1001]=3班}
true
-------keySet()-------
[李四,1002]=3班
[赵六,1004]=3班
[王五,1003]=4班
[张三,1001]=3班
-------entrySet()-------
[李四,1002]=3班
[赵六,1004]=3班
[王五,1003]=4班
[张三,1001]=3班

HashMap源码分析总结:

  1. HashMap刚创建时,table=null,size=0,节省空间,当添加第一个元素时,table容量调整为16
  2. 当元素个数大于阈值(16*0.75 = 12)时,会进行扩容,扩容后的大小为原来的两倍,目的是减少调整元素的个数
  3. jdk1.8 当每个链表长度 >8 ,并且数组元素个数 ≥64时,会调整成红黑树,目的是提高效率
  4. jdk1.8 当链表长度 <6 时 调整成链表
  5. jdk1.8 以前,链表时头插入,之后为尾插入

Hashtable类

线程安全,运行效率慢;不允许null作为key或是value

Properties类

hashtable的子类,要求key和value都是string,通常用于配置文件的读取

TreeMap类

实现了SortedMap接口(是map的子接口),可以对key自动排序

TreeSet是一个有序集合,可以以任意顺序将元素插入到集合中,在对集合进行遍历的时候,每个元素将自动按照排序后的顺序呈现。底层使用的是二叉树(更具体点是红黑树)实现,对于元素之间排序,如果不指定自定义的比较器Comparator,那么插入的对象必须实现Comparable接口,元素按照实现此接口的compareTo()方法去排序。如果指定了自定义的比较器Comparator,优先使用Comparator去对元素进行排序。比较规则决定了元素是否可以重复,以及元素的排序结果。

TreeSet 底层实际使用的存储容器就是 TreeMap。与 HashSet 完全类似的是,TreeSet 里绝大部分方法都是直接调用 TreeMap 的方法来实现的

TreeMap两种排序方式:

  • 让自定义的类实现Comparable 接口

    • 1.Student类中实现 Comparable< T >接口

      2.重写Comparable接口中的CompareTo方法

  • 创建一个比较类,并让其实现Comparator接口

    • 1.构造一个新的空 TreeMap,它根据指定比较器进行排序

      2.重写Comparator接口中的Compare方法

自定义的类实现Comparable 接口

【演示】

public class Student implements Comparable<Student> {
    private String name;
    private int stuNum;

    public Student(String name, int stuNum) {
        this.name = name;
        this.stuNum = stuNum;
    }

    @Override
    public int compareTo(Student o) {
        int x = this.stuNum - o.stuNum;// 若x等于0,则说明他们的学号相同
        return x;// 对学号进行排序
    }

    @Override
    public String toString() {
        return "[" + this.name + "," + this.stuNum + "]";
    }
}
package com.gather.treemap;

import java.util.Map;
import java.util.TreeMap;

public class Demo01 {
    public static void main(String[] args) {
        TreeMap<Student, String> students = new TreeMap<Student, String>();// 创建集合
        Student s1 = new Student("张三", 1001);
        Student s2 = new Student("李四", 1032);
        Student s3 = new Student("王五", 1013);
        Student s4 = new Student("赵六", 1024);
        students.put(s1, "3班");// 添加元素
        students.put(s2, "3班");// 键不能重复,值可以重复
        students.put(s3, "4班");
        students.put(s3, "8班");// s3不会被重复添加,但是其值会被替换("4班"会被替换为"8班"),因为Student类中重写了CompareTo方法
        students.put(s4, "5班");
        students.put(new Student("赵六", 1024), "1班");// 添加失败,但是会替换值("5班"会被替换为"1班"),因为Student类中重写了CompareTo方法
        System.out.println("元素个数为:" + students.size());
        System.out.println(students.toString());
        System.out.println(students.containsKey(new Student("赵六", 1024)));// true,因为Student类中重写了CompareTo方法
        // 遍历1:keySet()
        System.out.println("-------keySet()-------");
        for (Student s : students.keySet()) {
            System.out.println(s + "=" + students.get(s));
        }
        // 遍历2:entrySet()
        System.out.println("-------entrySet()-------");
        for (Map.Entry<Student, String> entry : students.entrySet()) {
            System.out.println(entry.getKey() + "=" + entry.getValue());
        }
    }
}
执行结果:
元素个数为:4
{[张三,1001]=3班, [王五,1013]=8班, [赵六,1024]=1班, [李四,1032]=3班}
true
-------keySet()-------
[张三,1001]=3班
[王五,1013]=8班
[赵六,1024]=1班
[李四,1032]=3班
-------entrySet()-------
[张三,1001]=3班
[王五,1013]=8班
[赵六,1024]=1班
[李四,1032]=3班

创建一个比较类,并让其实现Comparator接口

【演示】

public class Person {
    private String name;
    private int age;

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

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

    @Override
    public String toString() {

        return "[" + this.name + "," + this.age + "]";
    }
}
package com.gather.hashmap;

import java.util.Comparator;
import java.util.TreeMap;

public class Demo02 {
    public static void main(String[] args) {
        TreeMap<Person, Character> treeMap = new TreeMap<Person, Character>(new Comparator<Person>() {
            @Override
            public int compare(Person o1, Person o2) {
                int x = o1.getName().length() - o2.getName().length();
                int y = o1.getAge() - o2.getAge();
                return x == 0 ? y : x;// 先对名字长度排序,若名字长度一样,则按年龄大小排序
            }
        });
        Person p1 = new Person("张三", 16);
        Person p2 = new Person("孙悟空", 18);
        Person p3 = new Person("欧阳娜娜", 23);
        Person p4 = new Person("李四", 20);
        treeMap.put(p1, 'A');
        treeMap.put(p2, 'A');
        treeMap.put(p3, 'B');
        treeMap.put(p4, 'D');
        System.out.println("元素个数为:" + treeMap.size());
        System.out.println(treeMap.toString());
        System.out.println(treeMap.containsKey(new Person("欧阳娜娜", 23)));// true,重写了compare方法等同treeMap.containsKey(p3)
    }
}
执行结果:
元素个数为:4
{[张三,16]=A, [李四,20]=D, [孙悟空,18]=A, [欧阳娜娜,23]=B}
true

Collections工具类

方法 描述
public static <T extends Comparable<? super T>> void sort(List< T > list) 根据其元素的natural ordering对指定的列表进行排序
public static < T > int binarySearch(List<? extends T> list,T key,Comparator<? super T> c) 使用二叉搜索算法搜索指定对象的指定列表
public static < T > void copy(List<? super T> dest, List<? extends T> src) 将所有元素从一个列表复制到另一个列表中
public static void reverse(List<?> list) 反转指定列表中元素的顺序
public static void shuffle(List<?> list) 使用指定的随机源随机排列指定的列表

【演示】

package com.gather.collections;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class Demo01 {
    public static void main(String[] args) {
        List<Integer> list = new ArrayList<Integer>();
        list.add(10);
        list.add(88);
        list.add(24);
        list.add(66);
        System.out.println("排序之前:" + list.toString());
        Collections.sort(list);// 排序
        System.out.println("排序之后:" + list.toString());
        System.out.println(Collections.binarySearch(list, 88));// 利用二分法查找88的下标
        List<Integer> list2 = new ArrayList<Integer>();
        for (int i = 0; i < list.size(); i++) {
            list2.add(0);
        }
        Collections.copy(list2, list);// 复制元素是必须保证两个集合大小一样
        System.out.println("list2复制:" + list2);
        Collections.reverse(list);// 反转
        System.out.println("反转:" + list.toString());
        Collections.shuffle(list);// 打乱
        System.out.println("打乱:" + list.toString());
    }
}
执行结果:
排序之前:[10, 88, 24, 66]
排序之后:[10, 24, 66, 88]
3
list2复制:[10, 24, 66, 88]
反转:[88, 66, 24, 10]
打乱:[24, 66, 10, 88]

补充:数组与集合之间的转换

package com.gather.collections;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class Demo02 {
    public static void main(String[] args) {
        /*
        list转换成数组
        数组的大小必须小于集合的大小,否则多余的数组空间将赋默认值
         */
        List<Integer> list = new ArrayList<Integer>();
        list.add(10);
        list.add(88);
        list.add(24);
        list.add(66);
        Integer[] arr1 = list.toArray(new Integer[0]);// 此处Integer[0]中的0小于集合大小的4
        Integer[] arr2 = list.toArray(new Integer[8]);// 此处Integer[8]中的8大于集合大小的4,其余数组空间赋默认值
        System.out.println(arr1.length);
        System.out.println("arr1数组:" + Arrays.toString(arr1));
        System.out.println("arr2数组:" + Arrays.toString(arr2));
        /*
        数组转换为集合
        集合为受限集合,不能做添加、删除操作
        把基本类型数组转换为集合时,需要修改为相应的包装类
         */
        Integer[] array = {1, 3, 6, 8, 2};
        List<Integer> list2 = Arrays.asList(array);
        System.out.println("集合:" + list2.toString());
    }
}
执行结果:
4
arr1数组:[10, 88, 24, 66]
arr2数组:[10, 88, 24, 66, null, null, null, null]
集合:[1, 3, 6, 8, 2]

集合总结

集合的概念:对象的容器,和数组类似,定义了对多个对象进行操作的常用方法。

  • List集合:
    有序、有下标、元素可以重复。(ArrayList、LinkedList、Vector).

  • Set集合:

    无序、无下标、元素不可重复。(HashSet、TreeSet)

  • Map集合:
    存储一对数据,无序、无下标,键不可重复,值可重复。(HashMap、HashTable、TreeMap).

  • Collections集合工具类

    定义了除了存取以外的集合常用方法。

posted @ 2021-02-18 15:25  火车上的老头  阅读(41)  评论(0编辑  收藏  举报