# Java 集合框架

# 集合

# 1、集合的概念

对象的容器,实现对对象的常用操作,类似数组功能

# 2、集合和数组的区别

(1) 数组长度固定,集合长度不固定

(2) 数组可以存储基本类型和引用类型,集合只可以存储基本类型

# 3、位置

java.util*

# Collection 父接口

特点:代表一组任意类型的对象,无序,无下标、不能重复。

方法:

使用:

public class demo1 {
    public static void main(String[] args) {
        //创建集合
        Collection collection = new ArrayList();
        //(1)添加元素
        collection.add("苹果");
        collection.add("西瓜");
        System.out.println("元素个数:"+collection.size());
        System.out.println(collection);

        //(2)删除元素
        //collection.remove("苹果");
        //collection.clear();//清空

        //(3)遍历元素 (重点)
        //3.1增强for
        System.out.println("========3.1增强for=========");
        for (Object object:collection
             ) {
            System.out.println(object);

        }
        //3.2 使用迭代器(Iterator迭代器专门用来遍历集合的一种方式)
        //hasNext();有没有下一个元素
        //next();获取下一个元素
        //remove();删除当前元素
        System.out.println("========3.2 使用迭代器=========");
        Iterator it = collection.iterator();
        while (it.hasNext()){
            String s = (String)it.next();
            System.out.println(s);
            //在迭代过程中不能使用collection的删除方法
            //collection.remove(s);
            it.remove();
        }

        //(4)判断
        System.out.println(collection.contains("苹果"));
        System.out.println(collection.isEmpty());
    }
}
public class demo2 {//保存学生信息
    public static void main(String[] args) {
        //新建collection对象
        Collection collection = new ArrayList();
        Student s1 = new Student("张三",10);
        Student s2 = new Student("李四",10);
        Student s3= new Student("王五",10);
        //(1)添加数据
        collection.add(s1);
        collection.add(s2);
        collection.add(s3);
        System.out.println("元素个数"+collection.size());
        System.out.println(collection.toString());
        //(2)删除
        collection.remove(s1);

        //(3)遍历元素 (重点)
        //3.1增强for
        System.out.println("========3.1增强for=========");
        for (Object object:collection
        ) {
            Student s = (Student)object;
            System.out.println(s.toString());

        }
        //3.2 使用迭代器(Iterator迭代器专门用来遍历集合的一种方式)
        System.out.println("========3.2 使用迭代器=========");
        Iterator it = collection.iterator();
        while (it.hasNext()){
            Student s = (Student)it.next();
            System.out.println(s.toString());
        }

        //(4)判断
        System.out.println(collection.contains("s1"));
        System.out.println(collection.isEmpty());
    }

}

# List 子接口

特点:有序、有下标、元素可以重复

方法:

使用:

public class demo3 {
    public static void main(String[] args) {
        //先创建集合对象
        List list = new ArrayList<>();
        //(1)添加元素
        list.add("苹果");
        list.add("小米");
        list.add("华为");
        System.out.println("元素个数:"+list.size());
        System.out.println(list.toString());
        //(2)删除元素
        //list.remove("苹果");
        //list.remove(0);
        System.out.println("删除之后:"+list.size());
        System.out.println(list.toString());
        //(3)遍历
        //3.1使用for遍历
        System.out.println("=========使用for遍历=========");
        for (int i = 0; i < list.size(); i++) {
            System.out.println(list.get(i));
        }
        //3.2增强for
        System.out.println("=========增强for=========");
        for (Object object :
                list) {
            System.out.println(object);
        }
        //3.3使用迭代器
        System.out.println("=========使用迭代器=========");
        Iterator it = list.iterator();
        while(it.hasNext()){
            System.out.println(it.next());
        }
        //3.4使用列表迭代器,和Iterator区别,ListIterator可以向前或向后遍历,添加、删除、修改元素
        ListIterator lit = list.listIterator();
        System.out.println("=========使用列表迭代器从前往后=========");
        while (lit.hasNext()){
            System.out.println(lit.nextIndex()+":"+lit.next());
        }
        System.out.println("=========使用列表迭代器从后往前=========");
        while (lit.hasPrevious()){
            System.out.println(lit.previousIndex()+":"+lit.previous());
        }
        //(4)判断
        System.out.println(list.contains("苹果"));
        System.out.println(list.isEmpty());
        //(5)获取位置
        System.out.println(list.indexOf("华为"));
    }
}
public class demo4 {
    public static void main(String[] args) {
        //创建集合
        List list = new ArrayList();
        //(1)添加数字数据(自动装箱)
        list.add(20);
        list.add(30);
        list.add(40);
        list.add(50);
        list.add(60);
        System.out.println("元素个数"+list.size());
        System.out.println(list.toString());
        //(2)删除元素
        list.remove(0);
        list.remove(new Integer(20));
        //(3)补充方法 subList,返回子集合 ,含头不含尾
        List subList = list.subList(1, 3);
        System.out.println(subList.toString());//[40,50]


    }

}

# List 实现类

# ArrayList【重点】:

数组结构实现,查询快 、增删慢;

jdk1.2 版本,运行效率快、线程不安全。

public class demo5 {
    public static void main(String[] args) {
        // 创建集合 size 0 容量 0 扩容原来的 1.5 倍
        ArrayList arrayList = new ArrayList<>();
        //1、添加元素
        Student s1 = new Student("刘德华",20);
        Student s2= new Student("郭富城",22);
        Student s3 = new Student("梁朝伟",18);
        arrayList.add(s1);
        arrayList.add(s2);
        arrayList.add(s3);
        System.out.println("元素个数"+arrayList.size());
        System.out.println(arrayList.toString());
        //2、删除元素
        //arrayList.remove(s1);
        //arrayList.remove (new Student ("刘德华",20));// 这样删除的是新实例的 student,equals(this==obj) 需要重写 equals 方法
        //System.out.println ("删除之后"+arrayList.size () );//2
        //3、遍历元素【重点】
        //3.1 使用迭代器
        System.out.println("===========使用迭代器============");
        Iterator it = arrayList.iterator();
        while(it.hasNext()){
            Student s = (Student)it.next();
            System.out.println(s.toString());
        }
        //3.2 使用列表迭代器
        System.out.println("===========使用列表迭代器============");
        ListIterator lit = arrayList.listIterator();
        while(lit.hasNext()){
            Student s = (Student)lit.next();
            System.out.println(s.toString());
        }
        //4、判断
        System.out.println(arrayList.contains(new Student("梁朝伟",18)));// 已经重写过 equals 方法
        System.out.println(arrayList.isEmpty());
        //5、查找
        System.out.println(arrayList.indexOf(s1));
    }
}

重写 equals 方法

@Override
    public boolean equals(Object obj) {
        //1、判断是不是一个对象
        if(this == obj){
            return true;
        }
        //2、判断是否为空
        if(obj == null){
            return false;
        }
        //3、判断受否是 Student 类型
        if(obj instanceof Student){
            Student s = (Student)obj;
            //4、比较属性
            if(this.name.equals(s.getName())&&this.age == s.getAge()){
                return true;
            }
        }
        //5、不满足条件返回 flase
        return false;
    }

源码分析:

DEFAULT_CAPACITY = 10; 默认容量

​ 注: 如果没有向集合中添加任何元素时,容量为 0;添加任意一个元素时,容量为 10 每次扩容大小是原来的 1.5 倍

elementData 存放元素的数组

size 实际的元素个数

add() 添加元素

public boolean add(E e) {
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        elementData[size++] = e;
        return true;
    }
 private void ensureCapacityInternal(int minCapacity) {
        ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
    }
private static int calculateCapacity(Object[] elementData, int minCapacity) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            return Math.max(DEFAULT_CAPACITY, minCapacity);
        }
        return minCapacity;
    }
 private void ensureExplicitCapacity(int minCapacity) {
        modCount++;
        // overflow-conscious code
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }
private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        // minCapacity is usually close to size, so this is a win:
        elementData = Arrays.copyOf(elementData, newCapacity);
    }

# Vector:

数组结构实现,查询快、增删慢;

jdk1.0 版本,运行效率慢、线程安全

public class demo6 {
    public static void main(String[] args) {
        Vector vector = new Vector<>();
        vector.add("苹果");
        vector.add("西瓜");
        //3、遍历 使用枚举器
        Enumeration en = vector.elements();
        while(en.hasMoreElements()){
            String o = (String)en.nextElement();
            System.out.println(o);
        }
    }

# LinkedList:

链表结构实现,增删快,查询慢。

使用:

public class demo7 {
    public static void main(String[] args) {
        // 创建集合
        LinkedList linkedList = new LinkedList<>();
        //1、添加元素
        Student s1 = new Student("刘德华",20);
        Student s2= new Student("郭富城",22);
        Student s3 = new Student("梁朝伟",18);
        linkedList.add(s1);
        linkedList.add(s2);
        linkedList.add(s3);
        System.out.println("元素个数"+linkedList.size());
        System.out.println(linkedList.toString());
        //2、删除
        //linkedList.remove(s1);
        //System.out.println ("删除之后"+linkedList.size ());
        //linkedList.clear();
        //3、遍历
        //3.1 for 遍历
        System.out.println("==========for=============");
        for (int i = 0; i < linkedList.size(); i++) {
            System.out.println(linkedList.get(i));
        }
        //3.2 增强 for
        System.out.println("==========增强for=============");
        for (Object object :
                linkedList) {
            Student s = (Student) object;// 因为拿到以后变成 Object 所以需要强制类型转换
            System.out.println(s.toString());
        }
        //3.3 迭代器
        System.out.println("==========迭代器=============");
        Iterator iterator = linkedList.iterator();
        while (iterator.hasNext()) {
            Student s = (Student)iterator.next();
            System.out.println(s.toString());
        }
        //3.4 使用列表迭代器
        //4、判断
        System.out.println(linkedList.contains(s1));
        System.out.println(linkedList.isEmpty());
        //5、获取
        System.out.println(linkedList.indexOf(s1));
    }
}

源码分析:

int size 集合的大小

Node first 链表的头节点

Node last 链表的尾节点

void linkLast(E e) {
        final Node<E> l = last;
        final Node<E> newNode = new Node<>(l, e, null);
        last = newNode;
        if (l == null)
            first = newNode;
        else
            l.next = newNode;
        size++;
        modCount++;
    }
     private static class Node<E> {
        E item;
        Node<E> next;
        Node<E> prev;
        Node(Node<E> prev, E element, Node<E> next) {
            this.item = element;
            this.next = next;
            this.prev = prev;
        }
    }

# ArrayList 和 LinkedList 区别

# 泛型

# 泛型概述

Java 泛型是 JDK1.5 中引入的一个新特性,其本质是参数化类型,把类型作为参数传递。

常见形式有泛型类、泛型接口、泛型方法。

语法:

​ <T,....> T 称为类型占位符,表示一种引用类型

好处:

​ (1) 提高代码的重用性

​ (2)防止类型转换异常,提高代码的安全性

# 泛型类

语法:类名 <T>

public class MyGeneric<T> {// 泛型类
    // 使用泛型
    //1、创建变量
    T t;
    //2、泛型作为方法的参数
    public void show(T t){
        System.out.println(t);
    }
    //3、泛型作为方法的返回值
    public T getT(){
        return t;
    }
}
public class TestGeneric {
    public static void main(String[] args) {
        // 使用泛型类创建对象
        // 注意: 1、泛型只能使用引用类型, 2、不同泛型对象不能相互赋值
        MyGeneric<String> myGeneric = new MyGeneric<String>() ;
        myGeneric.t = "hello";
        myGeneric.show("大家好");
        String string = myGeneric.getT();
        MyGeneric<Integer> myGeneric2 = new MyGeneric<>();
        myGeneric2.t = 10;
        myGeneric2.show(20);
        Integer integer = myGeneric2.getT();
    }
}

# 泛型接口

语法:接口名 <T>

注意:不能泛型静态常量

public interface MyInterface <T>{// 泛型接口
    String name = "张三";
    T server(T t);
}
public class MyInterfaceImpl implements MyInterface<String>{
//1、实现类时确定泛型类型
    @Override
    public String server(String t) {
        System.out.println(t);
        return t;
    }
}
 MyInterfaceImpl impl = new MyInterfaceImpl();
 impl.server("xsdfdf");
 
 
 public class MyInterfaceImpl2<T> implements MyInterface<T>{
//2、实现类时继续使用泛型,实例时确认泛型
    @Override
    public T server(T t) {
        System.out.println(t);
        return t;
    }
}
  MyInterfaceImpl2<Integer> impl2 = new MyInterfaceImpl2<>();
        impl2.server(10000);

# 泛型方法

语法:<t> 返回值类型

public class MyGenericMethod {
    // 泛型方法
    public <T> void show(T t){
        System.out.println("泛型方法"+t);
    }
}
// 泛型方法  类型由传递的数据决定
        MyGenericMethod myGenericMethod = new MyGenericMethod();
        myGenericMethod.show("张三");
        myGenericMethod.show(200);

# 泛型集合

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

特点:

​ 编译时即可检查,而非运行时抛出异常。

​ 访问时,不必类型转换 (拆箱)。

​ 不同泛型之间引用不能相互赋值,泛型不存在多态。

ArrayList arrayList = new ArrayList();

不使用泛型创建的是 object 对象,添加不同类型数据时遍历需要判断不同类型会报错

public class demo8 {
    public static void main(String[] args) {
        ArrayList<String> arrayList = new ArrayList<String>();
        arrayList.add("aaa");
        arrayList.add("bbb");
        //arrayList.add (111);// 类型确定无法添加
        for (String string :
                arrayList) {
            System.out.println(string);
        }
        ArrayList<Student> arrayList2 = new ArrayList<Student>();
        Student s1 = new Student("刘德华",20);
        Student s2= new Student("郭富城",22);
        Student s3 = new Student("梁朝伟",18);
        arrayList2.add(s1);
        arrayList2.add(s2);
        arrayList2.add(s3);
        Iterator<Student> it = arrayList2.iterator();
        while(it.hasNext()){
            Student s = it.next();// 省去强制类型转换
            System.out.println(s.toString());
        }
    }
}

# Set 子接口

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

方法:全部继承自 Collection 中的方法。

public class demo1 {//Set 接口使用
    public static void main(String[] args) {
        // 创建集合
        Set<String> set = new HashSet<>();
        //1、添加数据
        set.add("苹果");
        set.add("华为");
        set.add("小米");
        //set.add ("小米");// 元素不可以重复
        System.out.println("数据个数"+set.size());//3
        System.out.println(set.toString());
        //2、删除数据
        set.remove("小米");
        //3、遍历
        //3.1、增强 for
        System.out.println("==========增强for===========");
        for (String string :
                set) {
            System.out.println(string);
        }
        //3.2、使用迭代器
        System.out.println("==========使用迭代器===========");
        Iterator<String> iterator = set.iterator();
        while (iterator.hasNext()) {
            System.out.println(iterator.next());
        }
        //4、判断
        System.out.println(set.contains("华为"));
        System.out.println(set.isEmpty());
        
    }
}

# HashSet【重点】

基于 HashCode 计算元素存放位置。

当存入元素的哈希码相同时,会调用 equals 进行确认,如结果为 true,则拒绝后者存入。

存储结构:哈希表(数组+链表+红黑树)
// 新建集合   后面 new 的 HashSet 的 & lt;> 中的 String jdk1.8 后可以不用写 
HashSet<String> hashSet = new HashSet<String>();
public class demo2 {//HashSet 集合的使用
    // 存储结构:哈希表(数组 + 链表 + 红黑树)
    public static void main(String[] args) {
        // 新建集合
        HashSet<String> hashSet = new HashSet<String>();
        //1、添加元素
        hashSet.add("刘德华");
        hashSet.add("梁朝伟");
        hashSet.add("周润发");
        //hashSet.add ("刘德华");// 重复添加不进去
        System.out.println("元素个数:"+hashSet.size());
        System.out.println(hashSet.toString());// 无序
        //2、删除数据
        //hashSet.remove ("刘德华");
        //3、遍历
        //3.1 增强 for
        
        //3.2、迭代器
        
        //4、判断
    }
}

# 存储过程:

(1) 根据 hashcode 计算保存的位置,如果这个位置为空,则直接保存,如果不为空,则执行第二步。

(2) 再执行 equals 方法,如果 equals 方法为 true,则认为是重复,否则,形成链表

// 快捷重写 hashCode 和 equals 右键 ----》generate====》hascode and equals

@Override
    public int hashCode() {
        int n1 = this.name.hashCode();
        int n2 = this.age;
        return n1+n2;
    }
 @Override
    public boolean equals(Object obj) {
        if(this == obj){
            return true;
        }
        if(obj == null){
            return false;
        }
        if(obj instanceof Person){
            Person p = (Person) obj;
            if(this.name.equals(p.getName())&&this.age == p.getAge()){
                return true;
            }
        }
        return false;
    }
//idea 生成的重写
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof Person)) return false;
        Person person = (Person) o;
        return getAge() == person.getAge() && Objects.equals(getName(), person.getName());
    }
    @Override
    public int hashCode() {
        return Objects.hash(getName(), getAge());
    }

重写的 hashCode 方法

(1) 31 是一个质数,减少散列冲突

(2) 31 提高执行效率 31*i = (i<<5)-i

image-20220913160918133

public class demo3 {
    public static void main(String[] args) {
        HashSet<Person> persons = new HashSet<>();
        //1、添加数据
        Person p1 = new Person("刘德华", 20);
        Person p2 = new Person("张学友", 22);
        Person p3 = new Person("梁朝伟", 18);
        persons.add(p1);
        persons.add(p2);
        persons.add(p3);
        //persons.add (p3);// 重复
        persons.add(new Person("刘德华",20));// 可以加进去,加的时候是 new Person
        // 重写 hashcode 方法和 equals 方法后就加不进去了 同理删除也可以了
        System.out.println("元素个数:"+persons.size());//3
        System.out.println(persons.toString());// 无序
        //2、删除
        //persons.remove(p1);
        //persons.remove (new Person ("刘德华",20);
        //3、遍历
        //3.1、增强 for
        for (Person person :
                persons) {
            System.out.println(persons.toString());
        }
        //3.2、迭代器
        Iterator<Person> iterator = persons.iterator();
        while (iterator.hasNext()) {
            System.out.println(iterator.next());
        }
        //4、判断
        System.out.println(persons.contains(p1));
        System.out.println(persons.isEmpty());
    }
}

# TreeSet

基于排列顺序实现元素不重复

实现了 SortedSet 接口,对集合元素自动排序

元素对象的类型必须实现 Comparable 接口,指定排序规则

public class Person implements Comparable<Person>{
 // 先按姓名比,再按年龄比 返回 0 则说明两个数据重复
    @Override
    public int compareTo(Person o) {
        int n1 = this.getName().compareTo(o.getName());
        int n2 = this.getAge() - o.getAge();
        return n1 == 0?n2:n1;
    }

通过 CompareTo 方法是否为重复元素。

存储结构:红黑树(二叉查找树)

public class demo4 {//TreeSet 使用
// 存储结构:红黑树
    // 要求:元素必须实现 Comparable 接口,comparareTo () 方法返回值为 0,认为是重复元素
    public static void main(String[] args) {
        // 创建集合
        TreeSet<Person> person = new TreeSet<>();
        //1、添加元素
        Person p1 = new Person("abc",20);
        Person p2 = new Person("dsdf",18);
        Person p3= new Person("dvd",11);
        person.add(p1);
        person.add(p2);
        person.add(p3);
        System.out.println("元素个数:"+person.size());
        System.out.println(person.toString());
        //2、删除 u
        //person.remove("abc",20);
        //3、遍历
        //4、判断
    }
}

基于红黑树排序

# Comparator 接口

实现 Comparator 定制比较

匿名内部类:匿名内部类可以使你的代码更加简洁,你可以在定义一个类的同时对其进行实例化。它与局部类很相似,不同的是它没有类名,java 如果某个局部类你只需要用一次,那么你就可以使用匿名内部类

TreeSet<Person> persons = new TreeSet<>(new Comparator<Person>()
public class demo5 {//Comparator 实现定制比较(比较器)
    public static void main(String[] args) {
        // 创建集合,并指定比较规则
        TreeSet<Person> persons = new TreeSet<>(new Comparator<Person>() {
           // 按年龄比
            @Override
            public int compare(Person o1, Person o2) {
                int n1 = o1.getAge() - o2.getAge();
                int n2 = o1.getName().compareTo(o2.getName());
                return n1 == 0?n2:n1;
            }
        });
        //1、添加元素
        Person p1 = new Person("abc",20);
        Person p2 = new Person("dsdf",18);
        Person p3= new Person("dvd",11);
        persons.add(p1);
        persons.add(p2);
        persons.add(p3);
        System.out.println("元素个数:"+persons.size());
        System.out.println(persons.toString());
    }
}

# TreeSet 案例

要求:使用 TreeSet 集合实现字符串按照长度进行排序

*helloword zhang lisi wnagwu beijing xian nanjing

public class demo6 {
    public static void main(String[] args) {
        TreeSet<String > treeSet = new TreeSet<>(new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                int n1 = o1.length() - o2.length();
                int n2 = o1.compareTo(o2);
                return n1 == 0?n2:n1;
            }
        });
        treeSet.add("helloword");
        treeSet.add("kisi");
        treeSet.add("beijing");
        treeSet.add("nanjing");
        treeSet.add("xian");
        System.out.println(treeSet.toString());
    }
}

# Map 集合

# Map 父接口

特点:存储一对数据(Key--Value),无序、无下标,键不可重复,值可重复。

方法:

使用:

无法添加重复的key  但是会把重复key的value替换掉

遍历:

1、使用 keySet();

Set<String> keySet = map.keySet();// 返回一个包含所有 key 的 set 集合

2、使用 entrySet 方法

一个 Entry 就是一个映射对

Set<Map.Entry<String, String>> entries = map.entrySet();// 返回 entry 映射对

entrySet 比 keySet 方法效率高

public class demo1 {//Map 接口使用
    public static void main(String[] args) {
        // 创建集合
        Map<String,String> map = new HashMap<>();
        //1、添加元素
        map.put("CN","中国");
        map.put("UK","英国");
        map.put("USA","美国");
        //map.put ("CN","zhongguo");// 无法添加重复的 key  但是会把重复 key 的 value 替换掉
        System.out.println("元素个数"+map.size());
        System.out.println(map.toString());
        //2、删除元素
        map.remove("USA");
        //3、遍历
        //3.1 使用 keySet ();
        System.out.println("========使用keySet();==========");
        //Set<String> keySet = map.keySet ();// 返回一个包含所有 key 的 set 集合
        for (String key :
                map.keySet()) {
            System.out.println(key+"-------"+map.get(key));
        }
        //3.2、使用 entrySet 方法
        System.out.println("========使用entrySet方法==========");
        Set<Map.Entry<String, String>> entries = map.entrySet();// 返回 entry 映射对
        for (Map.Entry<String, String> entry :
                entries) {
            System.out.println(entry.getKey()+"----------"+entry.getValue());
        }
        //4、判断
        System.out.println(map.containsKey("CN"));
        System.out.println(map.containsValue("中国"));
    }
}

# Map 集合的实现类

# HashMap

jdk1.2 版本,线程不安全,运行效率快;允许用 null 作为 key 或者 value

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

存储:使用 key 的 hashcode 和 equals 作为重复依据 参考 HashSet

public class demo2 {//HashMap 的使用
    public static void main(String[] args) {
        HashMap<Student, String> students = new HashMap<>();
        //1、添加元素
        Student s1 = new Student("孙悟空", 100);
        Student s2 = new Student("猪八戒", 101);
        Student s3 = new Student("沙悟净", 102);
        students.put(s1,"北京");
        students.put(s2,"上海");
        students.put(s3,"广东");
        //students.put (new Student ("孙悟空",100),"北京");// 可以添加,否则要重写 equals 和 hashcode 方法
        System.out.println("元素个数"+students.size());
        System.out.println(students.toString());
        //2、删除
        //students.remove(s1);
        //3、遍历
        //3.1 使用 keySet ();
        for (Student key :
                students.keySet()) {
            System.out.println(key+students.get(key));
        }
        //3.2 使用 entrySet ();
        for (Map.Entry<Student, String> entry :
                students.entrySet()) {
            System.out.println(entry.getKey()+entry.getValue());
        }
        //4、判断
        System.out.println(students.containsKey(s1));
        System.out.println(students.containsValue("北京"));
    }
}

源码分析:

static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; //aka 16//hashMap 初始容量大小
static final int MAXIMUM_CAPACITY = 1 << 30;//hashmap 的数组最大容量
static final float DEFAULT_LOAD_FACTOR = 0.75f;// 默认加载因子
static final int TREEIFY_THRESHOLD = 8;//jdk1.8 当链表长度大于 8 时,调整成红黑树
static final int UNTREEIFY_THRESHOLD = 6;//jdk1.8 当链表长度小于 6 时,调整成链表
static final int MIN_TREEIFY_CAPACITY = 64;//jkd1.8 当链表长度大于 8 时,并且集合元素个数大于等于 64 时调整成红黑苏
transient Node<K,V>[] table;// 哈希表中的数组
size;// 元素个数

刚创建 hashmap 之后没有添加元素时 table=null size=0 目的节省空间

public HashMap() {
    this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted
}

put 方法 没添加之前时 null 添加第一个元素长度为 16

public V put(K key, V value) {
    return putVal(hash(key), key, value, false, true);
}
static final int hash(Object key) {
        int h;
        return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
    }

总结:

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

HashSet 和 HashMap

实际上 hashSet 里面用的就是 hashMap

# Hashtable

jdk1.0 版本,线程安全,运行效率慢;不允许 null 作为 key 或者 value

# Properties

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

# TreeMap

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

使用:

需要实现 compara 方法

@Override
public int compareTo(Student o) {
    int n2 = this.stuNo - o.getStuNo();
    return n2;
}
public class demo3 {//TreeMap 的使用
    public static void main(String[] args) {
        TreeMap<Student, String> treeMap = new TreeMap<>();// 也可以定制比较参考 Comparator 接口
        //1、添加元素
        Student s1 = new Student("孙悟空", 100);
        Student s2 = new Student("猪八戒", 101);
        Student s3 = new Student("沙悟净", 102);
        treeMap.put(s1,"北京");
        treeMap.put(s2,"上海");
        treeMap.put(s3,"广东");
        treeMap.put(new Student("沙悟净", 102),"广东");
        System.out.println("元素个数"+treeMap.size());
        System.out.println(treeMap.toString());
        //2、删除
        //treeMap.remove(s1);
        //treeMap.remove (new Student ("孙悟空",100),"北京");
        //3、遍历
        //3.1 使用 keySet ();
        for (Student key :
                treeMap.keySet()) {
            System.out.println(key+treeMap.get(key));
        }
        //3.2 使用 entrySet ();
        for (Map.Entry<Student, String> entry :
                treeMap.entrySet()) {
            System.out.println(entry.getKey()+entry.getValue());
        }
        //4、判断
        System.out.println(treeMap.containsKey(s1));
        System.out.println(treeMap.containsValue("北京"));
    }
}

# Colletions 工具类

概念:集合工具类,定义了除了存取以外的集合常用方法

方法:

// 数组转成集合后变成受限集合,大小固定,不能添加和删除
List<String> list2 = Arrays.asList(names);
public class demo1 {//Collections 工具类使用
    public static void main(String[] args) {
        List<Integer> list = new ArrayList<>();
        list.add(20);
        list.add(10);
        list.add(15);
        list.add(30);
        list.add(40);
        list.add(50);
        //sort 排序
        System.out.println("排序之前"+list.toString());//[20, 10, 15, 30, 40, 50]
        Collections.sort(list);
        System.out.println("排序之后"+list.toString());//[10, 15, 20, 30, 40, 50]
        //binarySearch 二分查找
        int i = Collections.binarySearch(list,15);
        System.out.println(i);//1
        //copy 复制
        List<Integer> dest = new ArrayList<>();
        for (int k = 0; i < list.size(); k++) {//copy 需要两个集合大小一样,所以拿 0 填充
            dest.add(0);
        }
        Collections.copy(dest,list);
        System.out.println(dest.toString());
        //reverse 反转
        Collections.reverse(list);
        System.out.println("反转之后"+list);
        //shuffle 打乱
        Collections.shuffle(list);
        System.out.println("打乱之后"+list);
        // 补充:list 转成数组
        Integer[] arr = list.toArray(new Integer[0]);// 创建的数组大小小于集合大小则数组大小变成和集合大小一样,大于集合大小超出的为 null
        System.out.println(arr.length);
        System.out.println(Arrays.toString(arr));
        // 数组转成集合
        System.out.println("数组变成集合");
        String[] names = {"张三","李四","王五"};
        // 数组转成集合后变成受限集合,大小固定,不能添加和删除
        List<String> list2 = Arrays.asList(names);
        System.out.println(list2);
    }
}

# 总结