集合框架学习

集合框架

集合的概念

  • 概念:对象的容器,定义了对多个对象进行操作的常用方法。可实现数组的功能
  • 和数组区别:
    1. 数组长度固定,集合长度不固定
    2. 数组可以存储基本类型和引用类型,集合只能存储引用类型,不能存储基本类型
  • 位置:java.util.*;

Collection接口与实现类

Collection体系

在这里插入图片描述

  • Collection接口:该体系结构的根接口,代表一组对象,称为“集合”
  • List接口特点:有序、有下标、元素可重复
  • Set接口特点:无序、无下标、元素不可重复

Collection接口

  • 特点:代表一组任意类型的对象,无序、无下标、不能重复
  • 方法:
    • boolean add(Object obj) //添加一个对象
    • boolean addAll(Collection c) //将一个集合中的所有对象添加到此集合中
    • void clear() //清空此集合中的所有对象
    • boolean contains(Object o) //检查此集合中是否包含o对象
    • boolean equals(Object o) //比较此集合是否与指定对象相等
    • boolean isEmpty() //判断此集合是否为空
    • boolean remove(Object o) //在此集合中移除o对象
    • int size() //返回此集合中的元素个数
    • Object[] toArray() //将此集合转换成数组

Collection接口使用

  • 添加元素
  • 删除元素
  • 遍历元素
  • 检查集合是否为空

存储字符串

package com.yushuo.collection.demo01;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;

public class Demo01 {
    public static void main(String[] args) {
        /**
         * Collection接口使用
         * 添加元素
         * 删除元素
         * 遍历元素
         * 检查集合是否为空
         */
        //创建接口
        Collection collection = new ArrayList();
        
        //添加元素
        collection.add("苹果");
        collection.add("西瓜");
        collection.add("香蕉");
        System.out.println("集合中元素个数:" + collection.size());
        System.out.println(collection);//默认toString,强转String

        /*
        //删除元素
        //删除特定元素
        collection.remove("西瓜");
        System.out.println("删除特定元素之后,集合中元素个数:" + collection.size());
        System.out.println("删除特定元素之后,集合为:" + collection);//默认toString,强转String
        //清空
        collection.clear();
        System.out.println("清空之后,集合中元素个数:" + collection.size());
        System.out.println("清空元素之后,集合为:" + collection);//默认toString,强转String
         */

        //遍历元素【重点】
        //使用增强for
        for (Object o : collection) {
            System.out.println(o);//默认toString,强转String
        }
        //使用迭代器(迭代器,专门用来遍历集合的一种方法)
        /**
         * 使用迭代器(迭代器,专门用来遍历集合的一种方法)
         * hasNext();有没有下一个元素
         * next();获取下一个元素
         * remove();删除当前元素
         *
         * 迭代过程中,不允许使用collection的方法
         * 并发修改异常ConcurrentModificationException
         */
        /*
        Iterator iterator = collection.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next());//默认toString,强转String
            iterator.remove();
        }
        System.out.println("清空之后,集合中元素个数:" + collection.size());
        System.out.println("清空元素之后,集合为:" + collection);//默认toString,强转String
         */

        //检查集合是否为空
        System.out.println(collection.contains("桃子"));
        System.out.println(collection.contains("西瓜"));
    }
}

存储类

package com.yushuo.collection.demo02;

//学生类
public class Student {
    private String name;
    private int age;

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

    public Student() {
    }

    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 "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

package com.yushuo.collection.demo02;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;

public class Demo02 {
    public static void main(String[] args) {
        //collection使用,保存学生信息
        //创建Collection对象
        Collection collection = new ArrayList();
        Student student1 = new Student("张三",20);
        Student student2 = new Student("李四",21);
        Student student3 = new Student("王五",22);

        //添加学生数据,由于是ArrayList,可以重复添加
        collection.add(student1);
        collection.add(student2);
        collection.add(student3);
        System.out.println("集合的元素个数为:" + collection.size());
        //由于Student类重写了toString,因此显示的信息更详细
        System.out.println(collection);

        /*
        //删除学生数据
        collection.remove(student1);
        System.out.println("删除后集合的元素个数为:" + collection.size());
        System.out.println("删除后集合为:" + collection);
        collection.remove(new Student("李四",21));
        //无法删除,因为新创建的类与之前的类仅是内容相同,不是相同的类
        collection.clear();//清空,清空之后集合为空,但是Student对象还在
         */

        //遍历学生数据
        //增强for
        for (Object o : collection) {
            System.out.println(o);
        }
        //迭代器
        Iterator iterator = collection.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next());
        }

        //判断
        System.out.println(collection.contains(student1));//true
        System.out.println(collection.contains(new Student("张三",20)));//false
    }
}

List接口与实现类

List接口

  • 特点:有序、有下标、元素可重复
  • 方法:
    • void add(int index,Object o) //在index位置插入对象o
    • boolean addAll(int index,Collection c) //将一个集合中的元素添加到此集合的index位置
    • Object get(int index) //返回集合中指定位置的元素
    • List subList(int fromIndex,int toIndex) //返回fromIndex和toIndex之间的集合元素

List接口使用

存储字符串

package com.yushuo.list.demo01;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;

public class Demo01 {
    public static void main(String[] args) {
        //List接口:特点:有序、有下标、可以重复
        //创建List对象
        List list = new ArrayList();

        //添加对象
        list.add("苹果");
        list.add("西瓜");
        list.add(0,"香蕉");//在0位置添加对象
        System.out.println("集合的元素个数为:" + list.size());
        System.out.println("集合的元素为:" + list);

        /*
        //删除元素
        //list.remove("苹果");//删除元素"苹果"
        list.remove(1);//删除位置1的元素
        System.out.println("删除后,集合的元素个数为:" + list.size());
        System.out.println("删除后,集合的元素为:" + list);
         */

        //遍历元素
        //for
        for (int i = 0; i < list.size(); i++) {
            System.out.println(list.get(i));
        }
        //增强for
        for (Object o : list) {
            System.out.println(o);
        }
        //迭代器
        Iterator iterator = list.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next());
        }
        /**
         * 列表迭代器ListIterator
         * 与Iterator区别:
         * 可以向前向后遍历
         * 可以删除、修改元素
         */
        ListIterator listIterator = list.listIterator();
        //从前往后
        while (listIterator.hasNext()){
            System.out.println(listIterator.nextIndex() + ":" + listIterator.next());
        }
        //从后往前,执行完前面后,指针已经指向最末
        while (listIterator.hasPrevious()){
            System.out.println(listIterator.previousIndex() + ":" + listIterator.previous());
        }

        //判断
        System.out.println(list.contains("苹果"));//true
        System.out.println(list.isEmpty());//false

        //获取位置
        System.out.println(list.indexOf("苹果"));//1
        System.out.println(list.indexOf("葡萄"));//没有,返回-1
    }
}

存储数字数据

package com.yushuo.list.demo02;

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

public class Demo02 {
    public static void main(String[] args) {
        //List的使用,存储对象
        //创建List对象
        List list = new ArrayList();

        /**
         * 存储数字数据
         * 默认包含自动装箱操作
         * 集合无法存储基本类型,基本类型会自动装箱,为包装类
         */
        list.add(20);
        list.add(30);
        list.add(40);
        System.out.println("集合的元素个数为:" + list.size());
        System.out.println("集合的元素为:" + list);

        //删除元素
        list.remove(0);//删除特定位置的元素
        System.out.println("删除后的集合的元素个数为:" + list.size());
        System.out.println("删除后的集合的元素为:" + list);
        /*
        list.remove(20);
        输入的整数被认为是元素的位置,而不是元素本身
        删除特定的元素20
        list.remove((Object) 20);或者list.remove(new Integer(20));
        这里new Integer(20)可以使用是因为Integer的equals比较的是内容,不是地址
         */

        //返回子集合,范围fromIndex到toIndex-1
        System.out.println(list.subList(0,1));
    }
}

List实现类

ArrayList与LinkedList的区别:

  • ArrayList存储结构为数组,为连续的内存空间,查询快、增删慢
  • LinkedList存储结构为双向链表,为离散的内存空间,查询慢、增删快
ArrayList

ArrayList【重点】:

  • 数组结构实现,查询快、增删慢
  • JDK1.2版本,运行效率块、线程不安全
ArrayList的使用
package com.yushuo.list;

import java.util.Objects;

//学生类
public class Student {
    private String name;
    private int age;

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

    public Student() {
    }

    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 "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    /*
    @Override
    public boolean equals(Object obj) {
        //判断是否为同一个对象
        if (this == obj){
            return true;
        }
        //判断是否为空
        if (obj == null){
            return false;
        }
        //判断是否是Student相关类型
        if (obj instanceof Student){
            Student student = (Student) obj;
            //比较属性
            if (this.age == student.getAge() && this.name.equals(student.getName())){
                return true;
            }
        }
        //如果不满足属性相同
        return false;
    }
     */

    //以下为快捷键生成的
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Student student = (Student) o;
        return age == student.age && Objects.equals(name, student.name);
    }
}

package com.yushuo.list;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.ListIterator;

public class Demo03 {
    public static void main(String[] args) {
        /**
         * ArrayList的使用
         * 存储结构:数组,查找遍历速度快、增删慢
         */
        //创建集合
        ArrayList arrayList = new ArrayList();

        //添加元素,可重复
        Student student1 = new Student("张三",20);
        Student student2 = new Student("李四",21);
        Student student3 = new Student("王五",22);
        arrayList.add(student1);
        arrayList.add(student2);
        arrayList.add(student3);
        System.out.println("集合的元素个数为:" + arrayList.size());
        System.out.println("集合的元素为:" + arrayList);

        /*
        //删除元素,可以是元素或者位置
        arrayList.remove(student1);
        //arrayList.remove(new Student("李四",21));不会删除
        //因为二者内容相同但是地址不同,想要凭内容相同删除,需要重写equals
        arrayList.remove(new Student("李四",21));//重写后删除成功
        System.out.println("删除后的集合的元素个数为:" + arrayList.size());
        System.out.println("删除后的集合的元素为:" + arrayList);
         */

        //遍历元素【重点】
        //使用迭代器
        Iterator iterator = arrayList.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next());
        }
        //列表迭代器,顺序
        ListIterator listIterator = arrayList.listIterator();
        while (listIterator.hasNext()){
            System.out.println(listIterator.next());
        }
        //列表迭代器,逆序
        while (listIterator.hasPrevious()){
            System.out.println(listIterator.previous());
        }

        //判断
        System.out.println(arrayList.contains(student1));
        //因为equals重写了,所有返回true,没重写则为false
        System.out.println(arrayList.contains(new Student("张三",20)));
        System.out.println(arrayList.isEmpty());//false

        //查找
        System.out.println(arrayList.indexOf(student1));
    }
}
ArrayList源码分析
  • DEFAULT_CAPACITY = 10; 默认容量

    注意:如果没有向集合中添加任何元素时,容量为0,添加一个元素之后,容量为10

    初始容量为0,存放一个元素后扩容为10,之后每一次扩容,容量变为原本的1.5倍

  • elementData 存放元素的数组

  • size 实际元素个数

add()源码解析:

//初始size为0
public boolean add(E e) {
    ensureCapacityInternal(size + 1);  
    // Increments modCount!!
    //存放元素
    elementData[size++] = e;
    return true;
}

//确保数组有空间存储元素
private void ensureCapacityInternal(int minCapacity) {
    ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}

//计算所需容量,参数为存储元素的数组elementData与存放元素所需最小容量minCapacity
private static int calculateCapacity(Object[] elementData, int minCapacity) {
    //判断初始数组是否为空
    if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
        //数组为空时,比较所需最小容量与默认容量10,将较大值作为的计算结果
        return Math.max(DEFAULT_CAPACITY, minCapacity);
    }
    //数组非空时,计算得到的所需容量即为所需最小容量
    return minCapacity;
}

//确保数组有足够的容量,参数minCapacity为所需容量
private void ensureExplicitCapacity(int minCapacity) {
    modCount++;
    
    //如果所需容量超过现有数组大小,对数组进行扩充
    // overflow-conscious code
    if (minCapacity - elementData.length > 0)
        grow(minCapacity);
}

//扩充数组,参数为数组所需最小容量minCapacity,存储10个元素以后,每次扩容,容量变为原先的1.5倍
private void grow(int minCapacity) {
    // overflow-conscious code
    int oldCapacity = elementData.length;
    //oldCapacity >> 1右移一位即除2
    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

Vector:

  • 数组结构实现,查询快、增删慢
  • JDK1.0版本,运行效率慢、线程安全
Vector的使用
package com.yushuo.list;

import java.util.Enumeration;
import java.util.Vector;

public class Demo04 {
    public static void main(String[] args) {
        /**
         * Vector集合的使用
         * 存储结构:数组
         */
        //创建集合
        Vector vector = new Vector();

        //添加元素
        vector.add("苹果");
        vector.add("西瓜");
        vector.add("香蕉");
        System.out.println("集合的元素个数为:" + vector.size());
        System.out.println("集合的元素为:" + vector);

        //删除,可以根据下标或根据元素删除,也可清空

        //遍历
        //使用枚举器
        Enumeration enumeration = vector.elements();
        while (enumeration.hasMoreElements()){
            System.out.println(enumeration.nextElement());
        }

        //判断
        System.out.println(vector.contains("苹果"));//true

        //其他方法:firstElement()、lastElement()、elementAt(index)
    }
}
LinkedList

LinkedList:

  • 链表结构实现,增删快、查询慢
LinkedList的使用
package com.yushuo.list;

import java.util.Iterator;
import java.util.LinkedList;
import java.util.ListIterator;

public class Demo05 {
    public static void main(String[] args) {
        /**
         * LinkedList的使用
         * 存储结构:双向链表
         */
        //创建集合
        LinkedList linkedList = new LinkedList();

        //添加对象
        Student student1 = new Student("张三",20);
        Student student2 = new Student("李四",21);
        Student student3 = new Student("王五",22);
        linkedList.add(student1);
        linkedList.add(student2);
        linkedList.add(student3);
        System.out.println("集合的元素个数为:" + linkedList.size());
        System.out.println("集合的元素为:" + linkedList);

        /*
        //删除对象
        linkedList.remove(student1);
        System.out.println("集合的元素个数为:" + linkedList.size());
        System.out.println("集合的元素为:" + linkedList);
        linkedList.clear();//清空
         */

        //遍历对象
        //for
        for (int i = 0; i < linkedList.size(); i++) {
            System.out.println(linkedList.get(i));
        }
        //增强for
        for (Object o : linkedList) {
            System.out.println(o);
        }
        //迭代器
        Iterator iterator = linkedList.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next());
        }
        //列表迭代器,顺序
        ListIterator listIterator = linkedList.listIterator();
        while (listIterator.hasNext()){
            System.out.println(listIterator.next());
        }
        //逆序
        while (listIterator.hasPrevious()){
            System.out.println(listIterator.previous());
        }

        //判断
        System.out.println(linkedList.contains(student1));
        System.out.println(linkedList.isEmpty());

        //获取
        System.out.println(linkedList.indexOf(student2));
    }
}
LinkedList源码分析

first 头指针,指向链表的头节点

last 尾指针,指向链表的尾节点

add()

//初始size为0
public boolean add(E e) {
    ensureCapacityInternal(size + 1);  
    // Increments modCount!!
    //存放元素
    elementData[size++] = e;
    return true;
}

//确保数组有空间存储元素
private void ensureCapacityInternal(int minCapacity) {
    ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}

//计算所需容量,参数为存储元素的数组elementData与存放元素所需最小容量minCapacity
private static int calculateCapacity(Object[] elementData, int minCapacity) {
    //判断初始数组是否为空
    if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
        //数组为空时,比较所需最小容量与默认容量10,将较大值作为的计算结果
        return Math.max(DEFAULT_CAPACITY, minCapacity);
    }
    //数组非空时,计算得到的所需容量即为所需最小容量
    return minCapacity;
}

//确保数组有足够的容量,参数minCapacity为所需容量
private void ensureExplicitCapacity(int minCapacity) {
    modCount++;
    
    //如果所需容量超过现有数组大小,对数组进行扩充
    // overflow-conscious code
    if (minCapacity - elementData.length > 0)
        grow(minCapacity);
}

//扩充数组,参数为数组所需最小容量minCapacity,存储10个元素以后,每次扩容,容量变为原先的1.5倍
private void grow(int minCapacity) {
    // overflow-conscious code
    int oldCapacity = elementData.length;
    //oldCapacity >> 1右移一位即除2
    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);
}

泛型和工具类

泛型

泛型概念:

  • JDK5中引入,提供了编译时类型安全检测机制,该机制允许在编译时检测到非法的类型
  • 它的本质是参数化类型,也就是说所操作的参数类型被指定为一个参数
  • 参数化类型:将类型由原来的具体的类型参数化,然后在使用/调用时传入具体的类型
  • 这种参数类型可以在类、方法和接口中,分别称为泛型类、泛型方法、泛型接口

泛型定义格式:

  • <类型>:指定一种类型的格式,这里的类型可以看成是形参
  • <类型1,类型2, …>:指定多种类型的格式,多种类型之间用逗号隔开。这里的类型可以看成是形参
  • 将来具体调用时给定的类型可以看成是实参,并且实参的类型只能是引用数据类型

泛型优点:

  • 把运行时的问题提前到了编译器
  • 避免了强制类型转换
package com.yushuo.generic;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;

public class Demo01 {
    public static void main(String[] args) {
        //泛型
        //Collection集合存储字符串并遍历

        //创建集合对象,可以存储任意类型
        Collection collection = new ArrayList();

        //添加元素
        collection.add("hello");//类型是object
        collection.add("world");
        collection.add("java");
        //100被自动装箱为Integer类型
        collection.add(100);

        //遍历集合
        Iterator iterator = collection.iterator();
        while (iterator.hasNext()){
            /*
            Object obj = iterator.next();//存储的是Object类型
            System.out.println(obj);
             */
            //可以强制转换为String类型
            //报错ClassCastException,因为100是Integer类型的
            String str = (String) iterator.next();
            System.out.println(str);
        }
    }
}
package com.yushuo.generic.demo01;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;

public class Demo01_1 {
    public static void main(String[] args) {
        //泛型
        //Collection集合存储字符串并遍历

        //创建集合对象,限定单一类型String
        Collection<String> collection = new ArrayList<String>();

        //添加元素
        collection.add("hello");//类型是object
        collection.add("world");
        collection.add("java");
        //100被自动装箱为Integer类型
        //报错,因为只能存储单一类型String
        //把运行时会发生的问题提前在编译器就避免了
        //collection.add(100);

        //遍历集合
        Iterator<String> iterator = collection.iterator();
        while (iterator.hasNext()){
            //不需要强制类型转换
            String str = iterator.next();
            System.out.println(str);
        }
    }
}

泛型类

定义格式:

  • 格式:修饰符 class 类名<类型> {}

  • 范例:publiuc class Generic< T > {}

    此处T可以随便写为任意标示,常见的如T、E、K、V等形式的参数用于表示泛型

package com.yushuo.generic.demo02;

public class Student {
    private String name;

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

    public Student() {
    }

    public String getName() {
        return name;
    }

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

package com.yushuo.generic.demo02;

public class Teacher {
    private Integer age;

    public Teacher(Integer age) {
        this.age = age;
    }

    public Teacher() {
    }

    public Integer getAge() {
        return age;
    }

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

package com.yushuo.generic.demo02;

//泛型类
public class Generic<T> {
    private T t;

    public Generic() {
    }

    public Generic(T t) {
        this.t = t;
    }

    public T getT() {
        return t;
    }

    public void setT(T t) {
        this.t = t;
    }
}

package com.yushuo.generic.demo02;

public class Demo02 {
    public static void main(String[] args) {
        Student student = new Student();
        student.setName("张三");
        Teacher teacher = new Teacher();
        teacher.setAge(30);
        //teacher.setAge("30");编译出错
        System.out.println(student.getName());
        System.out.println(teacher.getAge());

        //上面两种类才能完成的事情,使用泛型类,一种类即可
        //只有类指定为泛型的属性才会被设置为String,其余的保持原因
        Generic<String> generic1 = new Generic<String>();
        generic1.setT("张三");
        Generic<Integer> generic2 = new Generic<Integer>();
        generic2.setT(20);
        System.out.println(generic1.getT());
        System.out.println(generic2.getT());
    }
}

泛型方法

定义格式:

  • 格式:修饰符 <类型> 返回值类型 方法名(变量类型 变量名){}
  • 范例:public < T > void show(T t){}
package com.yushuo.generic.demo03;
/*
public class Generic {
    public void show(String s){
        System.out.println(s);
    }

    public void show(Integer i){
        System.out.println(i);
    }

    public void show(Boolean b){
        System.out.println(b);
    }
}
 */

/*
//泛型类改进
public class Generic<T> {
    public void show(T t){
        System.out.println(t);
    }
}
 */

//泛型方法改进
public class Generic {
    public <T> void show(T t){
        System.out.println(t);
    }
}

package com.yushuo.generic.demo03;

public class Demo03 {
    public static void main(String[] args) {
        /*
        Generic generic = new Generic();
        generic.show("张三");
        generic.show(20);
        generic.show(true);
        //改进以前,generic.show(12.34);报错,因为没有提供对应类型参数的方法
         */

        /*
        //泛型类改进以后,每次创建对象都要明确类型
        Generic<String> generic1 = new Generic<String>();
        generic1.show("张三");
        Generic<Integer> generic2 = new Generic<Integer>();
        generic2.show(20);
        Generic<Boolean> generic3 = new Generic<Boolean>();
        generic3.show(true);
         */

        //如何创建时不明确,调用方法才明确——泛型方法
        //根据参数确定类型,传递什么类型参数,就是什么类型
        Generic generic = new Generic();
        generic.show("张三");
        generic.show(20);
        generic.show(true);
    }
}

泛型接口

定义格式:

  • 格式:修饰符 interface 接口名 <类型> {}
  • 范例:public interface Generic < T > {}
package com.yushuo.generic.demo04;

public interface Generic<T> {
    void show(T t);
}

package com.yushuo.generic.demo04;

//泛型接口实现类
public class GenericImpl<T> implements Generic<T>{
    @Override
    public void show(T t) {
        System.out.println(t);
    }
}

package com.yushuo.generic.demo04;

public class Demo04 {
    public static void main(String[] args) {
        GenericImpl<String> generic1 = new GenericImpl<String>();
        generic1.show("张三");
        GenericImpl<Integer> generic2 = new GenericImpl<Integer>();
        generic2.show(20);
    }
}

类型通配符

为了表示各种泛型List的父类,可以使用类型通配符

  • 类型通配符:<?>
  • List<?>:表示元素类型未知的List,它的元素可以匹配任何类型
  • 这种带通配符的List仅表示它是各种泛型的父类,并不能把元素添加到其中

如果我们不希望List<?>是任何泛型List的父类,只希望它代表某一类泛型List的父类,可以使用类型通配符的上限

  • 类型通配符上限:<? extends 类型>
  • List<? extends Number>:它表示的类型是Number或者其子类型

除了可以指定类型通配符的上限,我们也可以指定类型通配符的下限

  • 类型通配符下限:<? super 类型>
  • List<? super Number>:它表示的类型是Number或者其父类型
package com.yushuo.generic.demo05;

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

public class Demo05 {
    public static void main(String[] args) {
        //类型通配符:<?>
        List<?> list1 = new ArrayList<Object>();
        List<?> list2 = new ArrayList<Number>();
        List<?> list3 = new ArrayList<Integer>();

        //类型通配符上限:<? extends 类型>
        //List<? extends Number> list4 = new ArrayList<Object>();编译报错
        //上限是Number,因此不能是Number的父类Object
        List<? extends Number> list5 = new ArrayList<Number>();
        List<? extends Number> list6 = new ArrayList<Integer>();

        //类型通配符下限:<? super 类型>
        List<? super Number> list7  = new ArrayList<Object>();
        List<? super Number> list8 = new ArrayList<Number>();
        //List<? super Number> list9 = new ArrayList<Integer>();编译报错
        //下限是Number,因此不能是Number的子类Integer
    }
}

可变参数

可变参数

可变参数又称参数个数可变,用作方法的形参出现:

  • 格式:修饰符 返回值类型 方法名(数据类型… 变量名){}
  • 范例:public static int sum(int… a){}

可变参数注意事项:

  • 这里的变量其实是一个数组
  • 如果一个方法有多个参数,包含可变参数,可变参数要放最后
package com.yushuo.generic.demo06;

public class Demo06 {
    public static void main(String[] args) {
        System.out.println(sum(10,20));
        System.out.println(sum(10,20,30));
        System.out.println(sum(10,20,30,40));
    }

    public static int sum(int... a){
        //把多个参数放到数组a种
        int sum = 0;
        for (int i : a) {
            sum += i;
        }
        return sum;
    }
    
    /*
    可变参数需要放在最后
    因为可变参数会把所有参数存放在数组中,其之后的形参就没东西存放了
    public static int sum(int b,int... a){
    }
     */
}
可变参数的使用

Arrays工具类中有一个静态方法:

  • public static < T > List< T > asList(T… a):返回由指定数组支持的固定大小的列表

List接口中有一个静态方法:

  • public static < E > List< E > of (E… elements):返回包含任意数量元素的不可变列表

Set接口中有一个静态方法:

  • public static < E > Set< E > of(E… elements):返回一个包含任意数量元素的不可变集合
package com.yushuo.generic.demo07;

import java.util.Arrays;
import java.util.List;
import java.util.Set;

public class Demo07 {
    public static void main(String[] args) {

        //public static <T> List<T> asList(T... a):返回由指定数组支持的固定大小的列表
        //JDK8就有,元素可重复
        List<String> list1 = Arrays.asList("hello","world","java");

        //不能使用add和remove,因为二者会改变数组大小
        //list1.add("generic");
        //UnsupportedOperationException报错
        //list1.remove("hello");
        //UnsupportedOperationException报错
        //set可以使用,因为它不改变数组大小
        list1.set(1,"string");//[hello, string, java]
        System.out.println(list1);
        
        //public static <E> List<E> of (E... elements):返回包含任意数量元素的不可变列表
        //JDK9以后才有,元素可重复
        //List<String> list2 = List.of("hello","world","java");
        //add、remove、set都不能用

        //public static <E> Set<E> of(E... elements):返回一个包含任意数量元素的不可变集合
        //JDK9以后才有,元素不可重复
        //Set<String> set = Set.of("hello","world","java");
        //add、remove不可用,且不可用同字符的set方法
    }
}

Set接口与实现类

Set接口

  • 特点:无序、无下标、元素不可重复
  • 方法:全部继承自Collection中的方法

Set接口使用

基本和Collection相同

package com.yushuo.set;

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

public class Demo01 {
    public static void main(String[] args) {
        /**
         * Set接口使用
         * 特点:无序、无下标,元素不可重复
         */

        //创建集合
        Set<String> set = new HashSet<String>();

        //添加数据
        set.add("苹果");
        set.add("西瓜");
        set.add("香蕉");
        //即便添加多个重复元素,最后集合里面也只有1个元素
        System.out.println("集合的元素个数为:" + set.size());
        System.out.println("集合的元素为:" + set);

        /*
        //删除数据
        set.remove("苹果");
        System.out.println("删除后,集合的元素个数为:" + set.size());
        System.out.println("删除后,集合的元素为:" + set);
         */

        //遍历【重点】
        //增强for
        for (String s : set) {
            System.out.println(s);
        }
        //迭代器
        Iterator<String> iterator = set.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next());
        }

        //判断
        System.out.println(set.contains("苹果"));
        System.out.println(set.isEmpty());
    }
}

Set实现类

HashSet

HashSet【重点】:

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

存储过程:

  1. 根据hashcode计算保存的位置,如果此位置为空,则直接保存,如果不为空执行第二步
  2. 执行equals方法,如果equals方法为true,则认为是重复,否则,形成链表

HashSet存储字符串

package com.yushuo.set;

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

public class Demo02 {
    public static void main(String[] args) {
        /**
         * HashSet的使用,不允许元素重复
         * 存储结构:哈希表(数组 + 链表),jdk18之后还有红黑树
         */

        //创建集合,后面的String在jdk1.8以后可以不写
        HashSet<String> hashSet = new HashSet<String>();

        //添加元素,不允许元素重复,多个重复只会存1个
        hashSet.add("苹果");
        hashSet.add("西瓜");
        hashSet.add("香蕉");
        System.out.println("集合的元素个数为:" + hashSet.size());
        System.out.println("集合的元素为:" + hashSet);

        /*
        //删除元素
        hashSet.remove("苹果");
        System.out.println("删除后,集合的元素个数为:" + hashSet.size());
        System.out.println("删除后,集合的元素为:" + hashSet);
         */

        //遍历元素
        //增强for
        for (String s : hashSet) {
            System.out.println(s);
        }
        //迭代器
        Iterator<String> iterator = hashSet.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next());
        }

        //判断
        System.out.println(hashSet.contains("苹果"));
        System.out.println(hashSet.isEmpty());
    }
}

HashSet存储集合对象

package com.yushuo.set;

import java.util.Objects;

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

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

    public Person() {
    }

    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);
    }
}

package com.yushuo.set;

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

public class Demo03 {
    public static void main(String[] args) {
        /**
         * HashSet的使用,不允许元素重复
         * 存储结构:哈希表(数组 + 链表),jdk18之后还有红黑树
         */

        //创建集合,后面的String在jdk1.8以后可以不写
        HashSet<Person> hashSet = new HashSet<Person>();

        //添加元素,不允许元素重复,多个重复只会存1个
        //对于new Person,不会认作同一元素
        //可以重写hashcode与equals以使其被认作同一个
        //重写hashcode保证相同的元素得到相同的哈希码,否则可能被存到不同数组里面,依然无法认为是同一个
        Person person1 = new Person("张三",20);
        Person person2 = new Person("李四",21);
        Person person3 = new Person("王五",22);
        hashSet.add(person1);
        hashSet.add(person2);
        hashSet.add(person3);
        System.out.println("集合的元素个数为:" + hashSet.size());
        System.out.println("集合的元素为:" + hashSet);

        /*
        //删除元素
        //hashSet.remove(person1);
        //不重写hashcode与equals,不会被认为是同一个,删除不成功
        hashSet.remove(new Person("张三",20));
        System.out.println("删除后,集合的元素个数为:" + hashSet.size());
        System.out.println("删除后,集合的元素为:" + hashSet);
         */
        
        //遍历元素【重点】
        //增强for
        for (Person person : hashSet) {
            System.out.println(person);
        }
        //迭代器
        Iterator<Person> iterator = hashSet.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next());
        }
        
        //判断
        System.out.println(hashSet.contains(person1));
        System.out.println(hashSet.isEmpty());
    }
}
HashSet补充

hash码计算,使用31原因:

  1. 31是一个质数,可以减少散列冲突
  2. 使用31可以提高执行效率,31*i = (i<<5)-i,i乘31相当于左移5位再减i
public static int hashCode(Object a[]) {
    if (a == null)
        return 0;

    int result = 1;

    for (Object element : a)
        result = 31 * result + (element == null ? 0 : element.hashCode());

    return result;
}
TreeSet

TreeSet:

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

TreeSet存储字符串

package com.yushuo.set;

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

public class Demo04 {
    public static void main(String[] args) {
        /**
         * TreeSet的使用
         * 存储结构:红黑树
         * 不允许重复元素,多个重复元素只存储一个
         */

        //创建集合
        TreeSet<String> treeSet = new TreeSet<>();

        //添加元素。存储顺序以字符串的排列顺序,与添加顺序无关
        treeSet.add("张三");
        treeSet.add("李四");
        treeSet.add("王五");
        System.out.println("集合的元素个数为:" + treeSet.size());
        System.out.println("集合的元素为:" + treeSet);

        /*
        //删除元素
        treeSet.remove("张三");
        System.out.println("删除后,集合的元素个数为:" + treeSet.size());
        System.out.println("删除后,集合的元素为:" + treeSet);
         */

        //遍历
        //增强for
        for (String s : treeSet) {
            System.out.println(s);
        }
        //迭代器
        Iterator<String> iterator = treeSet.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next());
        }

        //判断
        System.out.println(treeSet.contains("张三"));
        System.out.println(treeSet.isEmpty());
    }
}

TreeSet存储数据

package com.yushuo.set.demo05;

import java.util.Objects;

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

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

    public Person() {
    }

    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);
    }

    //先比较姓名,再比较年龄
    @Override
    public int compareTo(Person o) {
        //比较姓名
        int n1 = this.getName().compareTo(o.getName());
        //比较年龄
        int n2 = this.getAge() - o.getAge();
        //若n1为0即姓名相同,比较年龄,因此返回n2,若n1不为0,则比较姓名,返回n1
        return n1 == 0 ? n2 : n1;
    }
}

package com.yushuo.set.demo05;

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

public class Demo05 {
    public static void main(String[] args) {
        /**
         * TreeSet存储数据
         * 存储结构:红黑树
         * 要求:元素必须要实现Comparable接口
         * CompareTo()返回0,认为是同一元素
         */

        //创建集合
        TreeSet<Person> treeSet = new TreeSet<>();

        //添加元素
        Person person1 = new Person("张三",20);
        Person person2 = new Person("李四",21);
        Person person3 = new Person("王五",22);
        treeSet.add(person1);
        treeSet.add(person2);
        treeSet.add(person3);
        //未实现接口以前,报错
        //ClassCastException: Person cannot be cast to java.lang.Comparable
        //原因:红黑树即二叉树需要比较,没有定义怎么比较
        System.out.println("集合的元素个数为:" + treeSet.size());
        System.out.println("集合的元素为:" + treeSet);

        /*
        //删除元素
        treeSet.remove(person1);
        //new也可以删除,因为之前实现接口时重写的CompareTo()方法比较的是姓名和年龄
        System.out.println("删除后,集合的元素个数为:" + treeSet.size());
        System.out.println("删除后,集合的元素为:" + treeSet);
         */

        //遍历元素
        //增强for
        for (Person person : treeSet) {
            System.out.println(person);
        }
        //迭代器
        Iterator<Person> iterator = treeSet.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next());
        }

        //判断
        System.out.println(treeSet.contains(person1));
        System.out.println(treeSet.isEmpty());
    }
}

Comparator接口

package com.yushuo.set.demo06;

import java.util.Objects;

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

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

    public Person() {
    }

    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);
    }

}

package com.yushuo.set.demo06;

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

public class Demo06 {
    public static void main(String[] args) {
        /**
         * TreeSet的使用
         * Comparator接口:实现定制比较(比较器)
         */

        //创建集合,并指定比较规则
        TreeSet<Person> treeSet = 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;
            }
        });

        //添加元素
        Person person1 = new Person("张三",20);
        Person person2 = new Person("李四",21);
        Person person3 = new Person("王五",22);
        treeSet.add(person1);
        treeSet.add(person2);
        treeSet.add(person3);
        //未实现接口以前,报错
        //ClassCastException: Person cannot be cast to java.lang.Comparable
        //原因:红黑树即二叉树需要比较,没有定义怎么比较
        System.out.println("集合的元素个数为:" + treeSet.size());
        System.out.println("集合的元素为:" + treeSet);
    }
}
TreeSet案例
package com.yushuo.set.demo07;

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

public class Demo07 {
    public static void main(String[] args) {
        /**
         * 要求:使用TreeSet集合实现字符串按照长度进行排序
         * hello world list zhang as number collection
         */
        //创建集合,并指定比较规则
        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("hello");
        treeSet.add("world");
        treeSet.add("list");
        treeSet.add("zhang");
        treeSet.add("as");
        treeSet.add("number");
        treeSet.add("collection");
        System.out.println(treeSet);
    }
}

Map接口与实现类

Map集合概述

map体系结构

在这里插入图片描述

Map接口特点:

  1. 用于存储任意键对应值(Key-Value)
  2. 键:无序、无下标、不允许重复(唯一)
  3. 值:无序、无下标、允许重复

Map接口的使用

  • 特点:

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

  • 方法:

    • V put(K Key,V Value) //将对象存入到集合中,关联键值。key重复则覆盖原值
    • Object get(Object key) //根据键获取对应的值
    • Set< K > //返回所有key
    • Collection< V > values() //返回包含所有制的Collection集合
    • Set<Map.Entry<K,V>> //键值匹配的Set集合
package com.yushuo.map.demo01;

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

public class Demo01 {
    public static void main(String[] args) {
        /**
         * Map接口的使用
         * 特点:
         * 存储键值对
         * 键不能重复,值可以重复
         * 无序
         */

        //创建Map集合
        Map<String, String> map = new HashMap<>();

        //添加元素
        map.put("cn","中国");
        map.put("uk","英国");
        map.put("usa","美国");
        System.out.println("集合的元素个数为:" + map.size());
        System.out.println("集合的元素为:" + map);

        /*
        //删除元素,根据键值Key删除
        map.remove("usa");
        System.out.println("删除后,集合的元素个数为:" + map.size());
        System.out.println("删除后,集合的元素为:" + map);
         */

        //遍历元素
        //使用keySet,map.keySet()返回Key的Set集合
        Set<String> keyset = map.keySet();
        for (String s : keyset) {
            //map.get()根据键值Key返回对应Value
            System.out.println(s + "————" + map.get(s));
        }
        /*
        或者
        for (String s : map.keySet()) {
            System.out.println(s + "————" + map.get(s));
        }
         */
        //使用entrySet,map.entrySet()返回键值对Key-Value的Map.Entry集合
        Set<Map.Entry<String, String>> entries = map.entrySet();
        for (Map.Entry<String, String> entry : entries) {
            System.out.println(entry.getKey() + "————" + entry.getValue());
        }
        /*
        或者
        for (Map.Entry<String, String> entry : map.entrySet()) {
            System.out.println(entry.getKey() + "————" + entry.getValue());
        }
         */

        //判断
        System.out.println(map.containsKey("cn"));
        System.out.println(map.containsValue("中国"));
        System.out.println(map.isEmpty());
    }
}

Map集合的实现类

HashMap、HashTable(跳过)、Properties

HashMap

HashMap【重点】:

  • JDK1.2版本,线程不安全,运行效率快,允许用null作为key或是value
HashMap的使用

存储数据

package com.yushuo.map.demo02;

import java.util.Objects;

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

    public Student() {
    }

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

    public String getName() {
        return name;
    }

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

    public int getStuNo() {
        return stuNo;
    }

    public void setStuNo(int stuNo) {
        this.stuNo = stuNo;
    }

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

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

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

package com.yushuo.map.demo02;

import com.yushuo.set.demo03.Person;

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

public class Demo02 {
    public static void main(String[] args) {
        /**
         * HashMap集合的使用
         * 存储结构:哈希表(数组 + 链表 + 红黑树)
         */

        //创建集合
        HashMap<Student, String> hashMap = new HashMap<>();

        //添加元素
        Student student1 = new Student("张三",1);
        Student student2 = new Student("李四",2);
        Student student3 = new Student("王五",3);
        //如果键值重复,后输入的value或覆盖旧的value
        //对于new的对象,如果没有重写,不会重复,依旧可以添加
        //重写hashCode和equals可以被认作重复
        hashMap.put(student1,"北京");
        hashMap.put(student2,"上海");
        hashMap.put(student3,"福州");
        //如果键值重复,后输入的value或覆盖旧的value
        System.out.println("集合的元素个数为:" + hashMap.size());
        System.out.println("集合的元素为:" + hashMap);

        /*
        //删除元素
        hashMap.remove(student1);
        System.out.println("删除后,集合的元素个数为:" + hashMap.size());
        System.out.println("删除后,集合的元素为:" + hashMap);
         */

        //遍历元素
        //使用keySet
        Set<Student> set = hashMap.keySet();
        //增强for
        for (Student student : set) {
            System.out.println(student + "————" + hashMap.get(student));
        }
        //迭代器
        Iterator<Student> iterator = set.iterator();
        while (iterator.hasNext()){
            Student student = iterator.next();
            System.out.println(student + "————" + hashMap.get(student));
        }
        /*
        或者
        for (Student student : hashMap.keySet()) {
            System.out.println(student + "————" + hashMap.get(student));
        }
         */
        //*******************************************************************
        //使用entrySet,返回的是Map.Entry类型
        Set<Map.Entry<Student, String>> entries = hashMap.entrySet();
        //增强for
        for (Map.Entry<Student, String> entry : entries) {
            System.out.println(entry.getKey() + "————" + entry.getValue());
        }
        //迭代器
        Iterator<Map.Entry<Student, String>> iterator1 = entries.iterator();
        while (iterator1.hasNext()){
            Map.Entry<Student, String> entry = iterator1.next();
            System.out.println(entry.getKey() + "————" + entry.getValue());
        }

        /*
        或者
        for (Map.Entry<Student, String> entry : hashMap.entrySet()) {
            System.out.println(entry.getKey() + "————" + entry.getValue());
        }
         */

        //判断
        System.out.println(hashMap.containsKey(student1));
        System.out.println(hashMap.containsValue("北京"));
        System.out.println(hashMap.isEmpty());
    }
}
HashMap源码分析

属性:

  • 默认初始容量大小:DEFAULT_INITIAL_CAPACITY = 16

  • 最大容量:MAXIMUM_CAPACITY = 2^30,2的30次方

  • 默认加载因子:DEFAULT_LOAD_FACTOR = 0.75,即当存储数据超过容量的75%时会扩容

  • 数组:table、容量:size

  • 阈值:TREEIFY_THRESHOLD = 8,MIN_TREEIFY_CAPACITY = 64,JDK1.8以后才有,基于数组的链表,当数组大小 > 64,链表长度 > 8时,链表会转为红黑树

  • UNTREEIFY_THRESHOLD = 6,当链表长度 < 6时,红黑树会转为链表

//构造方法
public HashMap() {
    //加载因子赋值
    this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted
}
public V put(K key, V value) {
    //hash(key)计算key的哈希码
    return putVal(hash(key), key, value, false, true);
}

final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
               boolean evict) {
    Node<K,V>[] tab;//数组
    Node<K,V> p;//对象
    int n, i;
    //添加第一个元素之前,数组为空,元素数量为0
    if ((tab = table) == null || (n = tab.length) == 0)
        //创建一个数组,数组大小为16
        n = (tab = resize()).length;
    //如果数组中没有元素
    if ((p = tab[i = (n - 1) & hash]) == null)
        //创建一个元素,存放再数组中
        tab[i] = newNode(hash, key, value, null);
    else {
        Node<K,V> e; K k;
        if (p.hash == hash &&
            ((k = p.key) == key || (key != null && key.equals(k))))
            e = p;
        else if (p instanceof TreeNode)
            e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
        else {
            for (int binCount = 0; ; ++binCount) {
                if ((e = p.next) == null) {
                    p.next = newNode(hash, key, value, null);
                    if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
                        treeifyBin(tab, hash);
                    break;
                }
                if (e.hash == hash &&
                    ((k = e.key) == key || (key != null && key.equals(k))))
                    break;
                p = e;
            }
        }
        if (e != null) { // existing mapping for key
            V oldValue = e.value;
            if (!onlyIfAbsent || oldValue == null)
                e.value = value;
            afterNodeAccess(e);
            return oldValue;
        }
    }
    ++modCount;
    //当元素个数超过容量的0.75时,扩充为原容量2倍
    if (++size > threshold)
        resize();
    afterNodeInsertion(evict);
    return null;
}

总结

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

HashSet就是用HashMap的Key保存数据

Hashtable(跳过)
  • JDK1.0版本,线程安全,运行效率慢,不允许null作为key或是value
Properties
  • Hashtable的子类,要求key和calue都是String。通常用于配置文件的读取
TreeMap
  • 实现了SortedMap接口(是Map的子接口),可以对key自动排序

存储对象

package com.yushuo.map.demo03;

import java.util.Objects;

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

    public Student() {
    }

    public Student(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 stuNo) {
        this.age = stuNo;
    }

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

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

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

    @Override
    public int compareTo(Student o) {
        int n1 = this.getName().compareTo(o.getName());
        int n2 = this.getAge() - o.getAge();
        return n1 == 0 ? n2 : n1;
    }
}

package com.yushuo.map.demo03;

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

public class Demo03 {
    public static void main(String[] args) {
        /**
         * TreeMap的使用
         * 存储结构:红黑树
         */

        //创建集合,如果Student不想写接口,可以定制比较
        TreeMap<Student, String> treeMap = new TreeMap<>();

        //添加元素
        Student student1 = new Student("张三",1);
        Student student2 = new Student("李四",2);
        Student student3 = new Student("王五",3);
        treeMap.put(student1,"北京");
        treeMap.put(student2,"上海");
        treeMap.put(student3,"福州");
        //ClassCastException: Student cannot be cast to java.lang.Comparable
        //TreeMap结构是红黑树,需要比较
        //Student需要实现Comparable接口
        //new也可以,因为重写了CompareTo
        System.out.println("集合的元素个数为:" + treeMap.size());
        System.out.println("集合的元素为:" + treeMap);

        /*
        //删除
        treeMap.remove(student1);
        System.out.println("删除后,集合的元素个数为:" + treeMap.size());
        System.out.println("删除后,集合的元素为:" + treeMap);
         */

        //遍历
        //使用keySet
        Set<Student> set = treeMap.keySet();
        //增强for
        for (Student student : set) {
            System.out.println(student + "————" + treeMap.get(student));
        }
        /*
        或者
        for (Student student : treeMap.keySet()) {
            System.out.println(student + "————" + treeMap.get(student));
        }
         */
        //迭代器
        Iterator<Student> iterator = set.iterator();
        while (iterator.hasNext()){
            Student student = iterator.next();
            System.out.println(student + "————" + treeMap.get(student));
        }
        //*************************************************************
        //使用entrySet
        Set<Map.Entry<Student, String>> entries = treeMap.entrySet();
        //增强for
        for (Map.Entry<Student, String> entry : entries) {
            System.out.println(entry.getKey() + "————" + entry.getValue());
        }
        /*
        或者
        for (Map.Entry<Student, String> entry : treeMap.entrySet()) {
            System.out.println(entry + "————" + treeMap.get(entry));
        }
         */
        //迭代器
        Iterator<Map.Entry<Student, String>> iterator1 = entries.iterator();
        while (iterator1.hasNext()){
            Map.Entry<Student, String> entry = iterator1.next();
            System.out.println(entry.getKey() + "————" + entry.getValue());
        }

        //判断
        System.out.println(treeMap.containsKey(student1));
        System.out.println(treeMap.containsValue("北京"));
        System.out.println(treeMap.isEmpty());
    }
}

TreeSet就是用TreeMap的Key保存数据

Collections工具类

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

  • 方法

    • public static void reverse(List<?> list) //反转及集合中元素的顺序

    • public static void shuffle(List<?> list) //随机重制集合元素的顺序

    • public static void sort(List<?> list) //升序排序(元素类型必须实现Comparable接口)

package com.yushuo.collectionsTools;

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

public class Demo01 {
    public static void main(String[] args) {
        //Collection工具类的使用

        //创建对象
        List<Integer> list = new ArrayList<>();
        list.add(20);
        list.add(15);
        list.add(8);
        list.add(26);
        list.add(3);
        list.add(10);
        System.out.println("排序之前:" + list);
        //sort排序
        Collections.sort(list);
        System.out.println("排序之后:" + list);

        //binarySearch二分查找,没找到返回-1
        int binarySearch = Collections.binarySearch(list,20);

        //copy复制
        List<Integer> dest = new ArrayList<>();
        for (int i = 0; i < list.size(); i++) {
            dest.add(0);
        }
        Collections.copy(dest,list);
        //IndexOutOfBoundsException: Source does not fit in dest
        //copy要求两个集合大小要一样,需要先对dest装入相同数量的元素
        System.out.println(dest);

        //reverse反转
        Collections.reverse(list);
        System.out.println("反转之后:" + list);

        //shuffle打乱
        Collections.shuffle(list);
        System.out.println("打乱之后:" + list);

        //补充1:list转成数组,参数不一定是0,随便都可以
        //如果参数未超过list大小,数组大小与list大小相同
        //如果参数超过list大小,数组大小为参数大小
        Integer[] arr = list.toArray(new Integer[0]);
        System.out.println(Arrays.toString(arr));

        //补充2:数组转成集合
        String[] names = {"张三","李四","王五"};
        //集合是一个受限集合,不能添加和删除
        List<String> list1 = Arrays.asList(names);
        System.out.println(list1);

        //把基本类型数组转成集合时,需要修改为包装类
        int[] nums = {100,200,300};
        List<int[]> list2 = Arrays.asList(nums);
        System.out.println(list2);//[[I@4554617c]
        //这样集合中的元素就只有一个,即一个数组了
        Integer[] num = {100,200,300};
        List<Integer> list3 = Arrays.asList(num);
        System.out.println(list3);//[100, 200, 300]
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值