JavaSE:集合框架

JavaSE:集合框架


前言

即使再小的帆也能远航


一、集合框架概述

  • 集合的概念
  • Collection接口
  • List接口与实现类
  • 泛型和工具类
  • Set接口与实现类
  • Map接口与实现类

二、集合概念

1.什么是集合

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

util包有两个顶层接口,一个collection,一个map

三、Collection接口(集合)

1. Collection体系集合

在这里插入图片描述

  • Collection:该体系结构的根接口,代表一组对象,成为“集合”
  • List接口的特点:有序、有下标、元素可重复
  • Set接口的特点:无序、无下标、元素不能重复
    ArrayList数组、LinkedList链表、Vector线程安全

2. Collection接口

  • Collection是个父接口
  • 特点:代表一组任意类型的对象,无序、无下标(所以不能用for循环直接调用,但可以用增强for循环foreach)、不能重复
  • 方法
    • boolean add(Object ibj) //添加一个对象
    • 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() //将此集合转换成数组
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;

/*
Collection的使用
1. 添加
2. 删除
3. 遍历
4. 判断
 */
public class Demo01 {
    public static void main(String[] args) {
        Collection collection = new ArrayList();
        //1. 添加
        collection.add("苹果");
        collection.add("西瓜");
        collection.add("榴莲");
        System.out.println("元素个数:"+collection.size());
        System.out.println(collection);
//        //2. 删除
//        collection.remove("榴莲");
//        System.out.println(collection);
//        //清空
//        collection.clear();
//        System.out.println(collection.size());
        //3. 遍历
        // 3.1 使用增强for  eg.collection.for
        for (Object o : collection) {
            System.out.println(o);
        }
        System.out.println("========");
        // 3.2 使用迭代器(专门用来遍历集合的一种方式)
        Iterator iterator = collection.iterator();
        while (iterator.hasNext()){
            Object o = iterator.next();
            System.out.println(o);
            //collection.remove(o);   //ConcurrentModificationException并发修改异常,不能同时修改又删除
//            iterator.remove();
//            System.out.println(o);
//            //删除功能最后执行
        }
//        System.out.println(collection);
        System.out.println("========");
        //4. 判断(包含)(判空)
        System.out.println(collection.contains("西瓜"));
        System.out.println(collection.isEmpty());
        collection.clear();
        System.out.println(collection.isEmpty());
    }
}
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;

/*
Collection的使用:保存学生信息
 */
public class Demo02 {
    public static void main(String[] args) {
        Collection collection = new ArrayList();
        Student s1 = new Student("张三",20);
        Student s2 = new Student("李四",18);
        Student s3 = new Student("王五",23);
        //1. 添加
        collection.add(s1);
        collection.add(s2);
        collection.add(s3);
        System.out.println(collection.size());
        System.out.println(collection);
        //2. 删除
        collection.remove(s1);
        System.out.println(collection.size());
        System.out.println(s1); //集合内该元素被删除(删的是指针),但是内存还在
        //有无以上这句话3.1的结果会不一样  3.2不变
        //3. 遍历
        //3.1 增强for
        for (Object o : collection) {
            System.out.println(o);
        }
        System.out.println("========");
        //3.2 迭代器
        Iterator iterator = collection.iterator();
        while (iterator.hasNext()){
            Student s = (Student)iterator.next();
            System.out.println(s);
        }
        //4. 判断
        System.out.println(collection.contains("张三"));
        System.out.println(collection.contains("李四"));
        System.out.println(collection.contains(s2));
        System.out.println(collection.isEmpty());
    }
}

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 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 o) {
        //1. 判断俩个对象是否是同一个引用,如果是那肯定相等
        if (this == o) return true;

        //2. 判断o是否为空以及是否是同一个类型,传进来空或者不是同一个类型的那肯定不相等
        if (o == null || getClass() != o.getClass()) return false;

        //3. 判断对象是否相等
        Student student = (Student) o;
        return age == student.age &&
                Objects.equals(name, student.name);
    }

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

    @Override
    protected void finalize() throws Throwable {
        //原方法体为空,为判断是否执行添加了输出语句
        System.out.println(this.name+"对象被回收了");
    }
}

1. List接口

  • List集合、List子接口
  • 特点:有序、有下标、元素可以重复
1. List使用
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;

/**
 * List子接口的使用
 * 特点:1. 有序 有下标  2. 可以重复
 */
public class Demo01 {
    public static void main(String[] args) {
        List list = new ArrayList();
        //1. 添加
        list.add("苹果");
        list.add("西瓜");
        list.add("榴莲");
        list.add("香蕉");
        System.out.println("元素个数:"+list.size());
        System.out.println(list);
        //2. 删除
        list.remove(0);
        list.remove("西瓜");
        System.out.println(list);
        System.out.println("========");
        //3. 遍历
        //3.1 使用for遍历
        for (int i = 0; i < list.size(); i++) {
            System.out.println(list.get(i));
        }
        System.out.println("========");
        //3.2 使用增强for
        for (Object o : list) {
            System.out.println(o);
        }
        //3.3 使用迭代器
        Iterator iterator = list.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next());
        }
        System.out.println("========");
        //3.4 列表迭代器
        //和Iterator的区别:
        //listIterator可以向前或向后遍历,添加、删除、修改元素
        ListIterator lit = list.listIterator();
        System.out.println("从前往后遍历:");
        while(lit.hasNext()){
            System.out.println(lit.nextIndex()+":"+lit.next());
        }
        System.out.println("========");
        System.out.println("从后往前遍历:");
        while(lit.hasPrevious()){
            System.out.println(lit.previousIndex()+":"+lit.previous());
        }
        System.out.println("========");
        //4. 判断
        System.out.println(list.contains("苹果"));
        System.out.println(list.isEmpty());
        //5. 获取位置
        System.out.println(list.indexOf("榴莲"));
    }
}

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

public class Demo02 {
    public static void main(String[] args) {
        List list = new ArrayList();
        //1. 添加  集合是不能保存基本类型的,所以会发生自动装箱
        list.add(20);
        list.add(30);
        list.add(40);
        System.out.println(list.size());
        System.out.println(list);
        //2. 删除
        //删除为20的数据的三种操作:把基本类型转为引用类型
//        list.remove("20");
//        list.remove((Object)20);
//        list.remove(new Integer(20));
        //3. 补充方法sublist,返回子集合,含头不含尾(左闭右开区间)
        List subList = list.subList(1, 2);
        System.out.println(subList);
        System.out.println(list.subList(1,3));
    }
}

2. List实现类
  • ArrayList实现类【重点】:
    • 数组结构实现,查询快、增删慢
    • JDK1.2版本后加入该类,运行效率快、线程不安全
  • Vector:
    • 数组结构实现,查询快、增删慢
    • JDK1.0版本后加入该类,运行效率慢、线程安全(加锁)
  • LinkedList:
    • 链表结构实现,增删快、查询慢
1. ArrayList
1. ArrayList使用
import java.util.ArrayList;
import java.util.Iterator;
import java.util.ListIterator;

/**
 * ArrayList的使用:
 * 存储结构:数组,查找遍历速度快,增删慢
 */
public class Demo03 {
    public static void main(String[] args) {
        ArrayList arrayList = new ArrayList();
        //1.添加
        Student s1 = new Student("张三",20);
        Student s2 = new Student("李四",18);
        Student s3 = new Student("王五",23);
        arrayList.add(s1);
        arrayList.add(s2);
        arrayList.add(s3);
        System.out.println("元素个数:"+arrayList.size());
        System.out.println(arrayList.toString());
        System.out.println("========");
        //2. 删除
//        arrayList.remove(s1);
//        System.out.println("删掉后元素个数:"+arrayList.size());
//        System.out.println(arrayList);
//        arrayList.remove(new Student("李四",18));
//        System.out.println(arrayList);
//        System.out.println("========");
        //3. 遍历
        //3.1 迭代器
        Iterator lt = arrayList.iterator();
        while(lt.hasNext()){
            Student s = (Student)lt.next();
            System.out.println(s.toString());
        }
        System.out.println("========");
        //3.2 ArrayList使用
        ListIterator lit = arrayList.listIterator();
        while (lit.hasNext()){
            Student s = (Student)lit.next();
            System.out.println(s);
        }
        System.out.println("========");
        while (lit.hasPrevious()){
            Student s = (Student)lit.previous();
            System.out.println(s);
        }
        System.out.println("========");
        //4. 判断
        System.out.println(arrayList.contains(new Student("李四",18)));
        System.out.println(arrayList.isEmpty());
        //5. 查找
        System.out.println(arrayList.indexOf(new Student("李四",18)));
    }
}

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 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 o) {
        //1. 判断俩个对象是否是同一个引用,如果是那肯定相等
        if (this == o) return true;

        //2. 判断o是否为空,传进来空的那肯定不相等
        if (o == null) return false;

        //3. 判断对象是否相等
        if (o instanceof Student) {
            Student student = (Student) o;
            //4. 比较属性
            if (this.name.equals(student.getName())&&this.age== student.getAge()) {
                return true;
            }
        }
        //5. 不满足条件 返回false
        return false;
    }

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

    @Override
    protected void finalize() throws Throwable {
        //原方法体为空,为判断是否执行添加了输出语句
        System.out.println(this.name+"对象被回收了");
    }
}

2. ArrayList源码分析
  • 默认容量 DEFAULT_CAPACITY = 10
    (刚创建没有向集合中添加元素时,容量为0,添加第一个元素后就扩容为10,容量不足时扩容,每次扩容大小是原来的1.5倍)
  • 存放元素的数组 elementData
  • 实际元素个数 size
  • 添加元素add()
2. Vector
1. Vector使用
import java.util.Enumeration;
import java.util.Vector;

/**
 * 演示Vector集合的使用
 * 存储结构:数组
 */
public class Demo04 {
    public static void main(String[] args) {
        Vector vector = new Vector();
        //1.添加
        vector.add("草莓");
        vector.add("芒果");
        vector.add("西瓜");
        System.out.println(vector.size());
        System.out.println(vector);
        //2. 删除
//        vector.remove(0);
//        System.out.println(vector);
//        vector.remove("西瓜");
//        System.out.println(vector);
//        vector.clear();
//        System.out.println(vector.size());
        //3. 遍历
        //使用枚举器
        Enumeration en = vector.elements();
        while (en.hasMoreElements()){
            String o = (String)en.nextElement();
            System.out.println(o);
        }
        System.out.println("========");
        //4. 判断
        System.out.println(vector.contains("西瓜"));
        System.out.println(vector.isEmpty());
        System.out.println("========");
        //5. 其他方法
        //firstElement、lastElement、elementAt
        System.out.println(vector.firstElement());
        System.out.println(vector.lastElement());
        System.out.println(vector.elementAt(1));
    }
}
3. LinkedList
1. LinkedList使用
  • 链表结构实现,增删快,查询慢
import java.util.Iterator;
import java.util.LinkedList;

/**
 * LinkedList的使用
 * 存储结构:双向链表
 */
public class Demo05 {
    public static void main(String[] args) {
        LinkedList linkedList = new LinkedList();
        Student s1 = new Student("张三",20);
        Student s2 = new Student("李四",18);
        Student s3 = new Student("王五",23);
        //1. 添加
        linkedList.add(s1);
        linkedList.add(s2);
        linkedList.add(s3);
        System.out.println(linkedList.size());
        System.out.println(linkedList);
        //2. 删除
        linkedList.remove(new Student("李四",18));
        System.out.println(linkedList);
//        linkedList.clear();
        //3. 遍历
        //3.1 for遍历
        System.out.println("========");
        for (int i = 0; i < linkedList.size(); i++) {
            System.out.println(linkedList.get(i));
        }
        //3.2 增强for
        System.out.println("========");
        for (Object o : linkedList) {
            Student s = (Student)o;
            System.out.println(o);
        }
        //3.3 使用迭代器
        System.out.println("========");
        Iterator it = linkedList.iterator();
        while(it.hasNext()){
            Student s = (Student)it.next();
            System.out.println(s);
        }
        //4. 判断
        System.out.println("========");
        System.out.println(linkedList.contains(s1));
        System.out.println(linkedList.isEmpty());
        //5. 获取
        System.out.println(linkedList.indexOf(s1));
        System.out.println(linkedList.indexOf(s2));
    }
}

2. LinkedList源码分析

(先学数据结构再看这个)

  • size 集合的大小
  • Node first 链表的头结点
  • Node last 链表的尾结点
4. ArrayList和LinkedList的区别
  • 不同结构实现方式
    • A:必须开辟连续空间,查询快,增删慢
    • L:无需开辟连续空间,查询慢,增删快

2. 泛型

1. 泛型概述
  • JDK1.5新特性,其本质是参数化类型,把类型作为参数传递
  • 常见形式有:泛型类、泛型接口、泛型方法
  • 语法<T,…> T称为类型占位符,表示一种引用类型(T或E、K、V都可)
  • 好处:
    • 提高代码的重用性
    • 防止类型转换异常,提高代码的安全性
2. 泛型类
/**
 * 泛型类
 * 语法:类名<T> 即写在类名后面
 * T是类型占位符,表示一种引用类型,如果编写多个可以使用逗号隔开
 */
public class Demo01<T> {
    //使用泛型T
    //1. 创建变量
    T t;
    //2. 泛型作为方法的参数
    public void show(T t){
        //T t1 = new T();   //因为类型不确定,所以是否能够被创建也不确定
        System.out.println(t);
    }
    //3. 泛型作为方法的返回值
    public T getT(){
        return t;
    }
}

public class Test01 {
    public static void main(String[] args) {
        //使用泛型类来创建对象
        // 注意:
        // 1. 泛型只能使用引用类型
        // 2. 不同泛型类型对象之间不能相互赋值
        Demo01<String> fanxing = new Demo01<String>();
        fanxing.t = "hello";
        fanxing.show("大家好!");
        String s = fanxing.getT();
        //fanxing.getT();

        Demo01<Integer> fanxing2 = new Demo01<Integer>();
        fanxing2.t = 100;
        fanxing2.show(200);
        Integer i = fanxing2.getT();
        //fanxing2.getT();


    }
}

3. 泛型接口
/**
 * 泛型接口
 * 语法:接口名<T>
 * 注意:不能泛型静态常量(static类同时加载,但此时泛型类型还不确定,无法被创建)
 */
public interface Demo02<T> {
    String name = "张三";
    T server(T t);

}

public class Demo02Impl implements Demo02<String>{

    @Override
    public String server(String s) {
        System.out.println(s);
        return s;
    }
}

public class Demo02Impl2<T> implements  Demo02<T>{
    
    @Override
    public T server(T t) {
        System.out.println(t);
        return t;
    }
}

//泛型接口
public class Test02 {
    public static void main(String[] args) {
        //一种是用之前确定类型,一种是用时确定类型
        //1. 用前确定
        Demo02Impl impl = new Demo02Impl();
        impl.server("Hello World!");
        //2. 用时确定
        Demo02Impl2<Integer> impl2 = new Demo02Impl2<>();
        impl2.server(520);
    }
}

4. 泛型方法
/**
 * 泛型方法 //MyGenericMethod
 * 语法:<T> 返回值类型
 */
public class Demo03 {

    //泛型方法  范围:方法内
    public <T> void show(T t){
        System.out.println("泛型方法:"+t);
    }

    //<T>声明泛型方法  T返回值类型 (T t)作为泛型参数
    public <T> T go(T t){
        System.out.println("泛型方法:"+t);
        return t;
    }
}

public class Test03 {
    public static void main(String[] args) {
        Demo03 demo03 = new Demo03();
        //泛型方法可传递任何类型
        demo03.show("Hello World"); //T-->String
        demo03.show(520);   //T-->Integer
        //上面的返回值类型为空,下面的返回值类型为泛型T
        Integer go = demo03.go(1314);
        //可以在调用方法前定义类型进行限制传递的类型
        demo03.<Double>go((double) 1314);
    }
}

5. 泛型好处
  • 好处:
    • 提高代码的重用性
    • 防止类型转换异常,提高代码的安全性
6. 泛型集合
  • 概念:参数化类型、类型安全的集合,强制集合元素的类型必须一致
  • 特点:
    • 编译时即可检查,而非运行时抛出异常
    • 访问时,不必类型转换(拆箱)
    • 不同泛型之间引用不能相互赋值,泛型不存在多态
import java.util.LinkedList;

public class Demo04 {
    public static void main(String[] args) {
        //LinkedList<E> 未指定类型时,默认为Object类型对象
        LinkedList linkedList = new LinkedList();
    }
}
import java.util.ArrayList;

public class Demo05 {
    public static void main(String[] args) {
        ArrayList arrayList = new ArrayList();
        arrayList.add("xxx");
        arrayList.add("yyy");
        arrayList.add(10);
        arrayList.add(20);
        System.out.println(arrayList);
        for (Object o : arrayList) {
            String str = (String)o;
            System.out.println(str);
//Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
        }
    }
}

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

public class Demo05_2 {
    public static void main(String[] args) {
        //限制泛型类型 为String
        ArrayList<String> arrayList = new ArrayList<String >();
        arrayList.add("xxx");
        arrayList.add("yyy");
        //限制泛型类型后,不能添加其他类型
//        arrayList.add(10);
//        arrayList.add(20);
        System.out.println(arrayList);
        for (Object o : arrayList) {
            System.out.println(o);
        }

        System.out.println("========");
        ArrayList<Student> arrayList1 = new ArrayList<Student>();
        Student s1 = new Student("张三",20);
        Student s2 = new Student("李四",18);
        Student s3 = new Student("王五",23);
        arrayList1.add(s1);
        arrayList1.add(s2);
        arrayList1.add(s3);

        Iterator<Student> it = arrayList1.iterator();
        while(it.hasNext()){
            Student s = it.next();
            System.out.println(s);
        }

        //不同泛型创建出来的对象不能相互赋值
        //arrayList1=arrayList;
    }
}

3. Set集合

1. Set集合概述
  • Set子接口
  • 特点:无序、无下标、元素不可重复
  • 全部继承自Collection中的方法
2. Set接口使用
  • Set实现类:
    • HashSet【重点】:
      • 基于HashCode实现元素不重复
      • 当存入元素的哈希码相同时,会调用equals进行确认,如结果为true,则拒绝后者存入
    • TreeSet:
      • 基于排列顺序实现元素不重复
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

/**
 * 测试Set接口的使用
 * 特点:(1)无序、没有下标 (2)不能重复
 */
public class Demo01 {
    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());
        System.out.println(set);    //[苹果, 华为, 小米]
        //2. 删除
        set.remove("小米");
        System.out.println(set);
        //3. 遍历
        //3.1 使用增强for
        System.out.println("========");
        for (String s : set) {
            System.out.println(s);
        }
        //3.2 使用迭代器
        System.out.println("========");
        Iterator<String > it = set.iterator();
        while (it.hasNext()){
            System.out.println(it.next());
        }
        //4. 判断
        System.out.println("========");
        System.out.println(set.contains("华为"));
        System.out.println(set.isEmpty());
    }
}

1. HashSet
1. HashSet使用
  • HashSet【重点】:
    • 基于HashCode实现元素不重复
    • 当存入元素的哈希码相同时,会调用equals进行确认,如结果为true,则拒绝后者存入
import java.util.HashSet;
import java.util.Iterator;

/**
 * HashSet集合的使用
 * 存储结构:哈希表(数组+链表+红黑树(JDK1.8))
 * 举例子:排队买票:排队的队伍是单向链表,购票的窗口是数组
 */
public class Demo02 {
    public static void main(String[] args) {
        HashSet<String > hashSet = new HashSet<>();
        //1. 添加
        hashSet.add("刘德华");
        hashSet.add("梁朝伟");
        hashSet.add("林志玲");
        hashSet.add("周润发");
        hashSet.add("刘德华");
        System.out.println("元素个数:"+hashSet.size());
        System.out.println(hashSet);
        //2. 删除
        hashSet.remove("刘德华");
        System.out.println("删除之后:"+hashSet.size());
        //3. 遍历
        //3.1增强for
        System.out.println("========");
        for (String s : hashSet) {
            System.out.println(s);
        }
        //3.2 使用迭代器
        System.out.println("========");
        Iterator<String > it = hashSet.iterator();
        while (it.hasNext()){
            System.out.println(it.next());
        }
        //4. 判断
        System.out.println(hashSet.contains("郭富城"));
        System.out.println(hashSet.isEmpty());
    }
}

import java.util.HashSet;

/**
 * HashSet集合的使用
 * 存储结构:哈希表(数组+链表+红黑树(JDK1.8))
 * 举例子:排队买票:排队的队伍是单向链表,购票的窗口是数组
 */
public class Demo03 {
    public static void main(String[] args) {
        HashSet<Person> person = new HashSet<>();
        //1. 添加
        Person p1 = new Person("刘德华",20);
        Person p2 = new Person("林志玲",22);
        Person p3 = new Person("梁朝伟",25);
        person.add(p1);
        person.add(p2);
        person.add(p3);
        person.add(p3);
        person.add(new Person("梁朝伟",25));
        System.out.println("元素个数:"+person.size());
        System.out.println(person.toString());  //不写默认也是调用toString方法
        
    }
}

2. HashSet存储方式
import java.util.HashSet;
import java.util.Iterator;

/**
 * HashSet集合的使用
 * 存储结构:哈希表(数组+链表+红黑树(JDK1.8))
 * 存储过程(重复依据):
 * (1)根据hashcode计算保存的位置,如果位置为空,则直接保存,如果不为空执行第二步
 * (2)再执行equals方法,如果equals方法为true,则认为重复,否则,完成链表
 * 举例子:排队买票:排队的队伍是单向链表,购票的窗口是数组
 */
public class Demo03 {
    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("梁朝伟",25);
        persons.add(p1);
        persons.add(p2);
        persons.add(p3);
        persons.add(p3); //失败
        persons.add(new Person("梁朝伟",25));   //失败!
        System.out.println("元素个数:"+persons.size());
        System.out.println(persons.toString());  //不写默认也是调用toString方法
        //2. 删除
        //persons.remove(p1);
        persons.remove(new Person("林志玲",22));
        System.out.println("删除之后:"+persons.size());
        //3. 遍历
        //3.1 使用增强for
        System.out.println("========");
        for (Person person : persons) {
            System.out.println(person);
        }
        //3.2 迭代器
        //set无序 没有列表迭代器
        System.out.println("========");
        Iterator<Person> it = persons.iterator();
        while (it.hasNext()){
            System.out.println(it.next());
        }
        System.out.println("========");
        //4. 判断
        System.out.println(persons.contains(p1));
        System.out.println(persons.contains(new Person("刘德华",20)));
    }
}

import java.util.Objects;

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

    public Person() {
    }

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

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

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

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

    @Override
    public int hashCode() {
        return Objects.hash(name, age);
    }
    //先重写hashcode保证相同属性对象生成相同哈希码值,不然俩个属性相同的对象依然可能会分到不同的数组
    @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);
    }
}

3. HashSet补充
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());
//(1)31是一个质数,减少散列冲突(2)31提高执行效率 31*i=(31<<5)-i
        return result;
    }
2. TreeSet
1. TreeSet概述
  • 红黑树(是二叉树的一种)
  • 基于排列顺序实现元素不重复
  • 实现了SortedSet接口,对集合元素自动排序
  • 元素对象的类型必须实现Comparatable接口,指定排序规则
  • 通过CompareTo方法确定是否为重复元素
2. TreeSet使用
import java.util.Iterator;
import java.util.TreeSet;

/**
 * TreeSet的使用
 * 存储结构:红黑树
 */
public class Demo05 {
    public static void main(String[] args) {
        TreeSet<String > treeSet = new TreeSet<>();
        //1. 添加
        treeSet.add("xyz");
        treeSet.add("abc");
        treeSet.add("hello");
        treeSet.add("xyz");
        System.out.println("元素个数:"+treeSet.size());
        System.out.println(treeSet.toString()); //[abc, hello, xyz]
        //2. 删除
        treeSet.remove("xyz");
        System.out.println("删除之后:"+treeSet.size());
        //3. 遍历
        //3.1 使用增强for
        System.out.println("========");
        for (String s : treeSet) {
            System.out.println(s);
        }
        //3.2 使用迭代器
        System.out.println("========");
        Iterator<String> it = treeSet.iterator();
        while(it.hasNext()){
            System.out.println(it.next());
        }
        //4. 判断
        System.out.println(treeSet.contains("abc"));
    }
}

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

/**
 * 使用TreeSet保存数据
 * 存储结构:红黑树(必须要对输入进集合的元素作比较)
 * 要求:元素必须要实现Comparable接口,ComparableTo()方法返回值为0,认为是重复元素
 */
public class Demo06 {
    public static void main(String[] args) {
        TreeSet<Person> persons = new TreeSet<>();
        //1. 添加
        Person p1 = new Person("xyz",20);
        //java.lang.ClassCastException: Person cannot be cast to java.lang.Comparable
        //所以要求元素必须实现Comparable接口才可进行比较(红黑树)存储
        Person p2 = new Person("hello",22);
        Person p3 = new Person("abc",25);
        Person p4 = new Person("abc",20);
        persons.add(p1);
        persons.add(p2);
        persons.add(p3);
        persons.add(p3);
        persons.add(p4);
        System.out.println("元素个数:"+persons.size());
        System.out.println(persons);    //小前大后
        //2. 删除
        persons.remove(new Person("abc",20));
        System.out.println("删除之后:"+persons.size());
        System.out.println(persons);
        //3. 遍历
        //3.1 使用增强fot
        System.out.println("========");
        for (Person person : persons) {
            System.out.println(person);
        }
        System.out.println("========");
        //3.2 使用迭代器
        Iterator<Person> it = persons.iterator();
        while(it.hasNext()){
            System.out.println(it.next());
        }
        System.out.println("========");
        //4. 判断
        System.out.println(persons.contains(new Person("abc",20)));
    }
}

import java.util.Objects;

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

    public Person() {
    }

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

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

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

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

    @Override
    public int hashCode() {
        return Objects.hash(name, age);
    }
    //先重写hashcode保证相同属性对象生成相同哈希码值,不然俩个属性相同的对象依然可能会分到不同的数组
    @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 compareTo(Person o) {
        int n1 = this.getName().compareTo(o.getName());
        int n2 = this.age-o.getAge();
        return n1==0?n2:n1;
        //先按姓名比,再按年龄比
        //如果没有CompareTo方法,红黑树无法进行比较存储,则会报错
    }
}

3. Comparator接口
import java.util.Comparator;
import java.util.TreeSet;

/**
 * TreeSet集合的使用
 * Comparator:实现定制比较(比较器)
 * Compatable:可比较的
 */
public class Demo07 {
    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;
            }
        });

        Person p1 = new Person("xyz",20);
        Person p2 = new Person("hello",22);
        Person p3 = new Person("abc",25);
        Person p4 = new Person("lisi",20);

        persons.add(p1);
        persons.add(p2);
        persons.add(p3);
        persons.add(p4);
        System.out.println(persons);
    }
}

4. TreeSet案例
import java.util.Comparator;
import java.util.TreeSet;

/**
 * 要求:使用TreeSet集合实现字符串按照长度进行排序
 * helloworld zhangsan lisi wangwu beijing xian nanjing
 */
public class Demo08 {
    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("helloworld");
        treeSet.add("zhangsan");
        treeSet.add("lisi");
        treeSet.add("wangwu");
        treeSet.add("beijing");
        treeSet.add("xian");
        treeSet.add("nanjing");
        System.out.println(treeSet);
    }
}

四、Map体系集合

1.Map集合概述

在这里插入图片描述
Map父接口

  1. 特点:
    1. 用于存储任意键值对(key-value)
    2. 键:无序、无下标、不允许重复(唯一)
    3. 值:无序、无下标、允许重复
  2. 方法:
    • V put (K key , V value) //将对象存入到集合中,关联键值。key重复则覆盖原值
    • Object get (Object key) //根据键获取对应的值
    • Set //返回所有Key
    • Collection values() //返回包含所有值的Collection集合
    • Set<Map.Entry<K,V>> //键值匹配的Set集合

2. Map接口使用

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

/**
 * Map接口的使用
 * 特点:(1)存储键值对(2)键不能重复,值可以重复(3)无序
 */
public class Demo01 {
    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");   //V put (K key , V value) //将对象存入到集合中,关联键值。key重复则覆盖原值
        System.out.println("元素个数:"+map.size());
        System.out.println(map);
        //2. 删除
        map.remove("usa");
        System.out.println("删除之后:"+map.size());
        //3. 遍历
        //3.1 使用KeySet(); 和 增强for
        System.out.println("========");
        Set<String> keySet = map.keySet();
        for (String key : keySet) {
            //for (String key : map.KeySet())
            System.out.println(key+":"+map.get(key));
        }
        System.out.println("========");
        //3.2 使用entrySet()
        //一个entry代表一个映射对,或者也叫一个键值对
        Set<Map.Entry<String, String>> entries = map.entrySet();
        for (Map.Entry<String, String> entry : entries) {
            System.out.println(entry.getKey()+":"+entry.getValue());
        }
//        map.entrySet().for
//        for (Map.Entry<String, String> entry : map.entrySet()) {
//
//        }
        //只需要取key,就用keySet来get(key),既取key又要value,就用map.entrySet();
        //entrySet效率高于keySet
        //4. 判断
        System.out.println("========");
        System.out.println(map.containsKey("cn"));
        System.out.println(map.containsValue("泰国"));

    }
}

3. Map集合的实现类

1. HashMap

  • HashMap【重点】:
    • JDK1.2,版本,线程不安全,运行效率快;允许用null作为key或是value
    • 存储结构:哈希表(数组+链表+红黑树)
    • 重复依据:键的hashCode()方法和equals方法
1. HashMap的使用
import java.util.HashMap;
import java.util.Map;

/**
 * HashMap集合的使用
 * 存储结构:哈希表(数组+链表+红黑树)
 * 使用key存储,可重写hashcode和equals作为重复
 */
public class Demo02 {
    public static void main(String[] args) {
        //创建集合
        HashMap<Student, String> students = new HashMap<Student,String>();
        //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(s3,"南京");
        students.put(new Student("沙和尚",102),"南京");
        //默认对比的是内存地址,可重写equals方法
        System.out.println("元素个数:"+students.size());
        System.out.println(students.toString());
        //2. 删除
        students.remove(s1);
        System.out.println("删除之后:"+students.size());
        //3. 遍历
        //3.1 使用KeySet();
        System.out.println("========");
        for (Student student : students.keySet()) {
            System.out.println(student+":"+students.get(student));
        }
        //3.2 使用entrySet();
        System.out.println("========");
        for (Map.Entry<Student, String> entry : students.entrySet()) {
            System.out.println(entry.getKey()+":"+entry.getValue());
        }
        //4. 判断
        System.out.println("========");
        System.out.println(students.containsKey(s1));
        System.out.println(students.containsKey(new Student("孙悟空",100)));
        System.out.println(students.isEmpty());
    }
}

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

2. HashMap源码分析
1. 属性
  • 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;
    默认加载因子(容量达75%时扩容)
  • 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;
    JDK1.8,当链表长度大于8时,并且集合元素个数大于等于64时,调整成红黑树
  • transient Node<K,V>[] table; //这里的table指的是哈希桶,面试必问
    哈希表中的数组
  • size //元素个数
2. 方法
  • 构造方法
    • 刚创建hashmap没填加元素时,table=null,size=0,目的节省空间
    • 一添加即扩容为初识容量大小16
    • 加载因子0.75时再次扩容
  • put添加元素方法
    • 先判断size,可resize方法扩容,后hash码值判断存放位置
3. 总结
  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以后是尾插入(头插入多线程下可能会产生死链)
  6. hashSet与hashMap有异有同
    1. 实现了不同接口
      • public class HashSet
        extends AbstractSet
        implements Set, Cloneable, java.io.Serializable
      • public class HashMap<K,V> extends AbstractMap<K,V>
        implements Map<K,V>, Cloneable, Serializable {
      • public HashSet(Collection<? extends E> c) {
        map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16));
        addAll©;
        }
3. HashTable和Properties
  • HashTable:
    • JDK1.0版本,线程安全,运行效率慢;不允许null作为key或是value
    • 现在已经不用了
    • 子类:Properties【重点】
      • 要求key和value都是String。通常用于配置文件的读取
      • 和IO流关系比较大

2. TreeMap

  • TreeMap:
    • 实现了SortedMap接口(是Map的子接口),可以对key自动排序
1. TreeMap的使用
import java.util.Comparator;
import java.util.Map;
import java.util.TreeMap;

public class Demo03 {
    public static void main(String[] args) {
        TreeMap<Student,String > treeMap = new TreeMap<Student,String>();
        //定制比较的比较器(匿名内部类)
//        TreeMap<Student,String > treeMap = new TreeMap<Student,String>(new Comparator<Student>() {
//            @Override
//            public int compare(Student o1, Student o2) {
//                return 0;
//            }
//        });
        //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);
        //2. 删除
//        treeMap.remove(s3);
//        System.out.println(treeMap.size());
//        treeMap.remove(new Student("猪八戒",101));
//        System.out.println(treeMap.size());
        //3. 遍历
        //3.1 使用keySet
        System.out.println("========");
        for (Student student : treeMap.keySet()) {
            System.out.println(student+":"+treeMap.get(student));
        }
        //3.2 使用entrySet()
        System.out.println("========");
        for (Map.Entry<Student, String> entry : treeMap.entrySet()) {
            System.out.println(entry.getKey()+":"+entry.getValue());
        }
        //4. 判断
        System.out.println(treeMap.containsKey(new Student("沙和尚",102)));
    }
}

import java.util.Objects;

public class Student implements Comparable<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);
    }

    @Override
    public int compareTo(Student o) {
//        int n1 = this.name.compareTo(o.getName());
        int n = this.stuNo-o.getStuNo();
        return n;
    }
}

五、Collections工具类

  • 概念:集合工具类,定义了除了存取以外的集合常用方法
  • 方法:
    • public static void reverse (List<?> list) //反转集合中元素的顺序
    • public static void shuffle(List<?> list) //随机重置集合元素的顺序
    • public static void sort(List list) //升序排序(元素类型必须实现Comparable接口)
import java.util.*;

/**
 * Collections工具类的使用
 */
public class Demo04 {
    public static void main(String[] args) {
        List<Integer> list = new ArrayList<>();
        list.add(20);
        list.add(5);
        list.add(12);
        list.add(30);
        list.add(6);
        //sort排序
        System.out.println("排序之前:"+list);
        Collections.sort(list);
        System.out.println("排序之后:"+list);
        System.out.println("========");
        //binarySearch
        int i = Collections.binarySearch(list,12);
        System.out.println(i);
        int j = Collections.binarySearch(list,13);
        System.out.println(j);  //负的,表示没找到
        System.out.println("========");
        //copy复制
        List<Integer> dest = new ArrayList<>();
        for (int k = 0; k < list.size(); k++) {
            dest.add(0);
        }
        Collections.copy(dest,list);
        System.out.println(dest);
        System.out.println("========");
        //reverse反转
        Collections.reverse(list);
        System.out.println("反转之后:"+list);
        System.out.println("========");
        //shuffle打乱
        Collections.shuffle(list);
        System.out.println("打乱之后:"+list);
        System.out.println("========");
        //补充:
        //list转成数组(散列)
        Integer[] array = list.toArray(new Integer[0]);
        System.out.println(array.length);
        System.out.println(Arrays.toString(array));
        //数组转成集合
        String[] names = {"张三","李四","王五"};
        List<String> list1 = Arrays.asList(names);  //转成后的集合是一个受限集合,不能添加和删除
//        List.add("赵六");
//        List.remove(0);
        System.out.println(list1);

        int[] nums = {100,200,300,400,500};
        List<int[]> list2 = Arrays.asList(nums);
        System.out.println(list2);  //有问题
        //把基本类型数组转成集合时,需要修改为包装类型
        Integer[] nums2 = {100,200,300,400,500};
        List<Integer> list3 = Arrays.asList(nums2);
        System.out.println(list3);  //成功
    }
}

六、总结

  • 集合的概念:
    • 对象的容器,和数组相似,定义了对多个对象进行操作的常用方法
  • List集合:
    • 有序、有下标、元素可以重复(ArrayList(数组)、LinkedList(双向链表)、Vector)
  • Set集合:
    • 无序、无下标、元素不可重复(HashSet(哈希表)、TreeSet(红黑树))
  • Map集合:
    • 存出一对数据,无序、无下标、键不可重复,值可重复(HashMap、HashTable(不用了)、TreeMap(Comparable接口))
  • Collections:
    • 集合工具类,定义了除了存取以外的集合常用方法

总结

即使再小的帆也能远航

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值