重温JavaSE15、16

发布时间:2024年01月13日

简要集合结构图(知道结构)在这里插入图片描述

数组的缺点:
  1. 数组一旦指定了长度,那么长度就被确定了,不可以更改。
  2. 删除,增加元素 效率低。
  3. 数组中真实元素的数量是没有办法获取的(可能有其他的值是没用到的),没有提供对应的方法或者属性来获取
  4. 数组存储:有序,可重复 ,对于无序的,不可重复的数组不能满足要求。

正因为上面的缺点,引入了一个新的存储数据的结构:集合

Collection接口(重点)(子类都有迭代器)

通过实现类创建对象:Collection collection = new ArrayList();//不能用子类特有的方法

Collection对象的方法(子类通用)说明返回值
add(E e)向集合添加元素e,若指定集合元素改变了则返回trueboolean
addAll(Collection<? extends E> c)把集合C的元素全添加到集合中,若指定集合元素改变返回trueboolean
clear()清空所有集合元素void
contains(Object o)判断指定集合是否包含对象oboolean
containsAll(Collection<?> c)判断指定集合是否包含集合c的所有元素boolean
isEmpty()判断指定集合的元素大小是否为0boolean
remove(Object o)删除集合中的元素对象o,若有多个o元素,则只删除第一个元素boolean
removeAll(Collection<?> c)删除指定集合包含集合c的元素,多个相同元素全删除boolean
retainAll(Collection<?> c)从指定集合中保留包含集合c的元素,其他元素则删除boolean
size()集合的元素个数int
toArray(T[] a)将集合转换为T类型的数组T[]
equals(Collection<?> c)比较两个集合中内容是否一样boolean
iterator()迭代器,用于循环遍历(每个集合都有对应的迭代器对象iterator)Iterator

看下面代码,要求会用

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

public class Demo1 {
    public static void main(String[] args) {
        //实例化
        Collection collection = new ArrayList();//不能用子类特有的方法
        ArrayList arrayList = new ArrayList();
        //添加元素add()、addAll(),集合可以存储不同类型的元素(很少这么做)
        collection.add("1233");
        collection.add(123);//自动装箱成Integer
        collection.add(123.2);//自动装箱成Double
        collection.add("1233");
        System.out.println(collection.size());//获得集合中真实的元素个数
        System.out.println(collection);//默认调用toString方法
        arrayList.addAll(collection);//把集合中的元素全部加到集合里
        //迭代器,循环遍历用的(每个集合类型都有对应的迭代器对象iterator,比for效率高)
        Iterator iterator = arrayList.iterator();
        while (iterator.hasNext()){//判断光标的下一位有没有元素
            Object next = iterator.next();
            System.out.println(next);
        }
        System.out.println(Arrays.toString(arrayList.toArray()));//转数组
        System.out.println("判断是否有该元素:"+arrayList.contains("123"));//类型也要一样
        //删除元素clear()、remove(值)
        arrayList.remove("1233");//移出先找到的一个值(只删一个)
        System.out.println(arrayList);
        System.out.println("移出前的arrayList"+arrayList+"\t移出前的collection"+collection);
        collection.removeAll(arrayList);//把该集合所有包含的值都删掉(包括相同的)
        System.out.println("移出后的arrayList"+arrayList+"\t移出后的collection"+collection);
        arrayList.clear();
        System.out.println(arrayList);
        System.out.println(arrayList.isEmpty());//判断集合是否为空[],不是null
        System.out.println(arrayList.equals(collection));//比较是否相同
    }
    /*
【集合】(容器)
两个图:
1.(一个一个存,有迭代器)Collection(下标无序,数据可重复)->List(下标有序,数据可重复)、Set(下标无序,数据不可重复)
List->ArrayList(线性表)(Vector是安全的,效率低)、LinkedList(链表)
Set->TreeSet(元素有序)、HashSet、LinkedHashSet元素有序

2.(一对一对存,没有迭代器)Map(key是无序的,数据不可重复,value是无序的,数据可重复)->TreeMap、HashMap

【六个接口】Collection
添加:add(值)、addAll(集合)
删除:clear()、remove(值)、removeAll()
查找:size()、cotains(值)
判断:isEmpty()、equals()
遍历:iterator()
转数组:toArray()
     */
}

迭代器iterator(重点,必须会用)

实例化:Iterator<类型> iterator = 集合对象.iterator();//直接通过集合对象.iterator().var快捷创建即可

iterator.方法()说明返回值
hasNext()判断光标的下一位有没有元素boolean
next()返回下一个元素,并且前进光标位置**还可通过IDEA的.var快捷生成对象**Object
remove()将迭代器返回的元素删除void

迭代器ListIterator(了解)

迭代和添加操作都是靠ListIterator来完成的:

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
public class Test2 {
    //这是main方法,程序的入口
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        list.add("aa");
        list.add("bb");
        list.add("cc");
        list.add("dd");
        list.add("ee");
        //在"cc"之后添加一个字符串"kk"
        ListIterator<String> it = list.listIterator();
        while(it.hasNext()){
            if("cc".equals(it.next())){
                it.add("kk");
            }
        }
        System.out.println(it.hasNext());
        System.out.println(it.hasPrevious());
        //逆向遍历:
        while(it.hasPrevious()){
            System.out.println(it.previous());
        }
        System.out.println(it.hasNext());
        System.out.println(it.hasPrevious());
        System.out.println(list);
    }
}
ListIterator迭代器方法说明
next ()返回列表中的下一个元素,并且前进光标位置
previous()返回列表中的下一个元素,并且后移动光标位置
hasNext()判断光标处是否还有下一个元素,有则返回true(正向遍历)
hasPrevious ()判断光标处是否还有上一个元素,有则返回true(逆向遍历)
remove()删除一个元素,使用remove时,迭代器的指针不能为初始位置,否则会报错
set(E e)用指定的元素替换由 next()或 previous()返回的最后一个元素
previous ()返回列表中的上一个元素,并向后 (上)移动光标位置
add(E e)将指定的元素插入列表的末尾

List接口(重点)(下标有序,数据可重复(不去重))

通过实现类创建对象:List list = new LinkedList();//不能用子类特有的方法

List接口的特有方法
父类共有方法在上面
简介说明(下标注意不能越界)返回值
add(int index, E ele)`在index位置插入ele元素,下标注意不能越界void
remove(int index) remove(Object o)`删除指定index位置的元素,下标注意不能越界
由于父类有该方法,默认为删除下标的元素
Object
set(int index, E ele)`设置指定index位置的元素为ele,下标注意不能越界Object
get(int index)`获取指定index位置的元素Object
addAll(int index, Collection eles)从index位置开始将eles中 的所有元素添加进来boolean
[last]indexOf(Object obj)返回obj在集合中首[末]次出现的下标,没有返回-1int
subList(int fromIndex, int toIndex)返回从fromIndex到toIndex 位置的子集合List

ArrayList[ArrayList遍历方式]和LinkedList[LinkedList遍历方式]遍历方式一样,下面不重复写了

List接口的遍历方式使用说明:
Iterator迭代器方式Iterator iterator = list对象.iterator();
while(iterator.hasNext()){
System.out.println(iterator.next());
}
省内存的迭代器方式for(Iterator<类型> it = list对象.iterator();it.hasNext(); ){
System.out.println(it.next());
}
增强for循环,底层也是迭代器实现的for(类型 变量名 : list对象){
System.out.println(变量名);
}
普通for循环,少用for(int i = 0;i < list对象.size();i++){
System.out.println(list对象.get(i));
}

循环内获取集合中的单个对象都可通过IDEA的.var快捷生成对象

在这里插入图片描述

//遍历方法
ArrayList arrayList1 = new ArrayList(100);//声明了一个容量为100的空数组
arrayList.add("111");
arrayList.add("123");
Iterator iterator = arrayList.iterator();
while(iterator.hasNext()){
    System.out.println(iterator.next());
}
for(Iterator<String> it = arrayList.iterator();it.hasNext();){
    System.out.println(it.next());
}
for(String i : arrayList){
    System.out.println(i);
}
for(int i = 0;i < arrayList.size();i++){
    System.out.println(arrayList.get(i));
}
数组转集合的方法:
数组转集合的方法说明返回值
Arrays.asList(数组)将数组转换成集合List

看下面代码,要求会用

public static void main(String[] args) {
    List list = new LinkedList();//声明接口new实现类,不能用子类特有的方法
    list.add(0,"123");//刚传入的下标位置只能按顺序,否则会下标越界
    list.add(123);
    list.add(0,"aaa");//添加到第一个位置,其他后移
    System.out.println(list);
    list.set(0,"bbb");
    System.out.println(list.get(0));;//根据下标获取元素
    list.remove(2);//根据下标删除,不能下标越界,父类也有该方法,默认安装下标删除
    System.out.println("元素ccc下标"+list.indexOf("ccc"));//查找元素,存在返回下标,不存在返回-1
    for(Iterator it = list.iterator(); it.hasNext();){
        System.out.println("内容:"+it.next());
    }
}
/*
    List,下面方法是父类没有,自己特有的
添加:add(下标,值)
删除:remove(下标)
查找:get(下标)、indexOf(值)
修改:set(下标,值)
     */

ArrayList(重点,常用)

  1. ArrayList底层是Object[]
  2. Object[]初始空间长度是10个,满额后扩容50%

创建对象:ArrayList<引用数据类型> arrayList = new ArrayList<>();

ArrayList遍历方式和LinkedList遍历方式一样,看上面List遍历

ArrayList方法(和List一致)说明返回值
add(E e)向集合添加元素e,若指定集合元素改变了则返回trueboolean
add(int index, E ele)在index位置插入ele元素,下标注意不能越界void
addAll(Collection<? extends E> c)把集合C的元素全添加到集合中,若指定集合元素改变返回trueboolean
addAll(int index, Collection eles)从index位置开始将eles中 的所有元素添加进来int
clear()清空所有集合元素void
remove(int index)删除指定index位置的元素,下标注意不能越界(默认)Object
remove(Object o)删除集合中的元素对象o,若有多个o元素,则只删除第一个元素boolean
removeAll(Collection<?> c)删除指定集合包含集合c的元素,多个相同元素全删除boolean
retainAll(Collection<?> c)从指定集合中保留包含集合c的元素,其他元素则删除boolean
set(int index, E ele)设置指定index位置的元素为ele,下标注意不能越界Object
get(int index)获取指定index位置的元素Object
[last]indexOf(Object obj)返回obj在集合中首[末]次出现的下标,没有返回-1boolean
size()集合的元素个数int
contains(Object o)判断指定集合是否包含对象oboolean
containsAll(Collection<?> c)判断指定集合是否包含集合c的所有元素boolean
isEmpty()判断指定集合的元素大小是否为0boolean
equals(Collection<?> c)比较两个集合中内容是否一样boolean
toArray(T[] a)将集合转换为T类型的数组T[]
subList(int fromIndex, int toIndex)返回从fromIndex到toIndex 位置的子集合List
iterator()迭代器,用于循环遍历(每个集合都有对应的迭代器对象iterator)Iterator

和List一样,会用即可

import java.util.ArrayList;
import java.util.Vector;

public class Demo3 {
    public static void main(String[] args) {
        ArrayList arrayList = new ArrayList();//底层是声明了一个容量为10的空数组,当空间不够扩容50%,有size变量专门记录数据个数的,数组没有
//        Vector arrayList = new Vector();//基本和arrayList一样,扩容1倍
        ArrayList arrayList1 = new ArrayList(100);//声明了一个容量为100的空数组
        arrayList.add("111");
        arrayList.add("123");
        System.out.println(arrayList);
    }
    /*
        和List方法一样
        1.ArrayList底层是Object[]
        2.Object[]初始空间长度是10个,满额后扩容50%
        3.ArrayList底层size属性,记录Object[]真实的元素个数
     */
}

Vector(了解)

和ArrayList用法一致。

线程安全,空间满额后按1倍扩容,早期集合容器(和ArrayList一样,但很少用了)

Vector和ArrayList的区别和联系

实现原理相同,功能相同,都是长度可变的数组结构,很多情况下可以互用

两者的主要区别如下

  1. Vector是早期JDK接口,ArrayList是替代Vector的新接口
  2. Vector线程安全,ArrayList重速度轻安全,线程不安全
  3. 长度需增长时,Vector默认增长一倍,ArrayList增长50%

泛型<>(重点,要会用)

使用泛型原因:

? Object做参数的话,参数都要向下类型转换,有可能类型不一致导致出错。且不能用子类的特有方法。
? 泛型<>做参数的话,不需要类型转换,类型统一,操作简单(只出现在编译器,运行期消失)(后期反射是运行期,可硬元素)

总结:
  1. 1.5版本以后出现的
  2. 泛型实际就是 一个<>引起来的参数类型,这个参数类型 具体在使用的时候才会确定具体的类型。
  3. 使用了泛型以后,可以确定集合中存放数据的类型,在编译时期就可以检查出来。
  4. 泛型的类型:都是引用数据类型,不能是基本数据类型。
好处:

取出元素时,由于是统一类型,遍历等方面操作简单。


看下面简单的泛型案例

public static void main(String[] args) {
    ArrayList<Integer> list = new ArrayList<>();//jdk1.7后面可以写成<>或不写了
    list.add(999);
    list.add(333);
    list.add(666);
    list.add(1);
    for (Integer i:list) {
        System.out.print(i+",");
    }
}

LinkedList(偏重点,会用即可)

LinkedList底层是链表

创建对象:LinkeList<引用数据类型> arrayList = new LinkeList<>();

LinkedList遍历方式和ArrayedList遍历方式一样,看上面List遍历

LinkedList常用方法(数据可重复)说明红色表示的是特有方法返回值
add(E e)、addLast(E e)在链表后添加一个元素evoid
add(int index, E e)在指定下标index插入一个元素evoid
addFirst(E e)在链表头部插入一个元素evoid
offerFirst(E e)在链表头部插入一个元素eboolean
offer(E e)、offerLast(E e)在链表尾部添加一个元素eboolean
poll()、pollFirst()、remove()、removeFirst()删除第一个元素并返回(poll为空返回null,remove为空抛异常)E
pollLast()、removeLast()删除最后一个元素并返回(poll为空返回null,remove为空抛异常)E
clear()清空链表void
element()、getFirst()获取第一个元素(为空抛出异常)E
getLast()获取最后一个元素E
.get(i)获取下标i的对应元素E
[last]indexOf(Object o)根据元素查询第一次出现的下标位置int
peek()、peekFirst()查询表头元素E
peekLast()查询表尾元素E
iterator()迭代器,用于循环遍历(每个集合都有对应的迭代器对象iterator)Iterator

和List一样,会用即可

public static void main(String[] args) {
    LinkedList<String> list = new LinkedList();//相当于链表
    list.add("123");
    list.add("234");
    list.add(1,"aaa");//下标不能越界,找1下标是效率低,加入元素是效率高的
    list.addFirst("常");//特有方法,头插法,0下标位置插入
    list.addLast("哲");//特有方法,尾插法,size-1下标位置插入
    list.add("456");
    System.out.println(list);
    System.out.println(list.getFirst());//获取头结点
    System.out.println(list.getLast());//获取尾结点
    list.addLast("1");//没返回值,常用,因为语义化能看懂
    System.out.println(list.offerLast("1"));//返回boolean,很少用
    list.removeFirst();//链表空抛异常
    list.pollFirst();//链表空返回null
    System.out.println("===============================");
    for(int i = 0;i < list.size();i++){
        System.out.println();
    }
}

源码分析(了解)

public class LinkedList<E>{//E是一个泛型,具体的类型要在实例化的时候才会最终确定
    transient int size = 0;//集合中元素的数量
    //Node的内部类
    private static class Node<E> {
        E item;//当前元素
        Node<E> next;//指向下一个元素地址
        Node<E> prev;//上一个元素地址

        Node(Node<E> prev, E element, Node<E> next) {
            this.item = element;
            this.next = next;
            this.prev = prev;
        }
    }
    transient Node<E> first;//链表的首节点
    transient Node<E> last;//链表的尾节点
    //空构造器:
    public LinkedList() {
    }
    //添加元素操作:
    public boolean add(E e) {
        linkLast(e);
        return true;
    }
    void linkLast(E e) {//添加的元素e
        final Node<E> l = last;//将链表中的last节点给l 如果是第一个元素的话 l为null
        //将元素封装为一个Node具体的对象:
        final Node<E> newNode = new Node<>(l, e, null);
        //将链表的last节点指向新的创建的对象:
        last = newNode;
        if (l == null)//如果添加的是第一个节点
            first = newNode;//将链表的first节点指向为新节点
        else//如果添加的不是第一个节点 
            l.next = newNode;//将l的下一个指向为新的节点
        size++;//集合中元素数量加1操作
        modCount++;
    }
    //获取集合中元素数量
    public int size() {
        return size;
    }
    //通过索引得到元素:
    public E get(int index) {
        checkElementIndex(index);//健壮性考虑
        return node(index).item;
    }
    Node<E> node(int index) {
        //如果index在链表的前半段,那么从前往后找
        if (index < (size >> 1)) {
            Node<E> x = first;
            for (int i = 0; i < index; i++)
                x = x.next;
            return x;
        } else {//如果index在链表的后半段,那么从后往前找
            Node<E> x = last;
            for (int i = size - 1; i > index; i--)
                x = x.prev;
            return x;
        }
    }
}

Set接口(重点)(无下标,无序,数据不可重复(去重))

通过实现类创建对象:Set set = new HashSet();//不能用子类特有的方法

Set对象的方法(子类通用)说明返回值
add(E e)向集合添加元素e,若指定集合元素改变了则返回trueboolean
addAll(Collection<? extends E> c)把集合C的元素全添加到集合中,若指定集合元素改变返回trueboolean
clear()清空所有集合元素void
contains(Object o)判断指定集合是否包含对象oboolean
containsAll(Collection<?> c)判断指定集合是否包含集合c的所有元素boolean
isEmpty()判断指定集合的元素大小是否为0boolean
remove(Object o)删除集合中的元素对象o,若有多个o元素,则只删除第一个元素boolean
removeAll(Collection<?> c)删除指定集合包含集合c的元素,多个相同元素全删除boolean
retainAll(Collection<?> c)从指定集合中保留包含集合c的元素,其他元素则删除boolean
size()集合的元素个数int
toArray(T[] a)将集合转换为T类型的数组T[]
equals(Collection<?> c)比较两个集合中内容是否一样boolean
iterator()迭代器,用于循环遍历(每个集合都有对应的迭代器对象iterator)Iterator

HashSet遍历方式[HashSet遍历方式]和TreeSet遍历方式一样[TreeSet遍历方式]

Set接口的遍历方式使用说明:
Iterator迭代器方式Iterator iterator = Set对象.iterator();
while(iterator.hasNext()){
System.out.println(iterator.next());
}
省内存的迭代器方式for(Iterator<类型> it = Set对象.iterator();it.hasNext(); ){
System.out.println(it.next());
}
增强for循环,底层也是迭代器实现的for(类型 变量名 : Set对象){
System.out.println(变量名);
}

看下面代码,理解去重即可

public static void main(String[] args) {
        Set<String> set = new HashSet<>();
        set.add("3");
        set.add("2");
        set.add("1");
        set.add("5");
        set.add("aaa");
        set.add("5");//相同数据不会添加进去,直接忽略
        System.out.println(set.size());
        set.remove("2");//返回boolean,没有根据下标删除的方法
        System.out.println(set);
        Iterator<String> iterator = set.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next());
        }
    }
    /*
【Set接口】(位置无序(不能下标找值了),数据不可重复)(去重的功能)
都是Collection的方法
     */

HashSet(重点,常用)(无下标、无序、数据不可重复(去重))

一般情况下:调用equals()方法是用来比较两个对象之间属性值是否相同,相同返回true,不同返回false
所以比较对象的时候我们要重写equals()方法

hashCode():

? 源码:public native int hashCode();
? 介绍:底层采用哈希算法,将程序中对象的内存地址转换成hash值。
一般情况下,重写equals()后,也要重写hashCode()方法

去重原理:
  1. 首先在add()方法中获得要添加的元素的值

  2. hashCode值不同则认为是不同的对象,直接添加入集合

    hashCode值相同(因为hashCode有可能是多个数相加,所以值还是可能一致的),通过equals()进行比较

  3. 比较结果为false不是相同对象,进行存储

    比较结果为true则是相同对象,不进行存储

注意:
  1. 如果使用HashSet存储系统类型对象,可直接使用
  2. 如果使用HashSet存储自定义类型对象,需要重写对应类的hashCode()和equals()方法 快捷键:alt+insert

创建对象:HashSet<引用数据类型> set = new HashSet<>();

HashSet遍历方式和TreeSet遍历方式一样,看上面Set遍历


看下面代码重写hashCode()和equals()解析

import java.util.Objects;
public class Student{//比较器接口,TreeSet用的
    private String id;
    private String name;
    private int age;
    public Student(String id, String name, int age) {
        this.id = id;
        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;
    }
    public String getId() {
        return id;
    }
    public void setId(String id) {
        this.id = id;
    }
    //重写该类的hashCode()和equals()方法,实现相同的人的去重(快捷键alt+insert)
    @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(id, student.id) && Objects.equals(name, student.name);
    }
    @Override
    public int hashCode() {
        return Objects.hash(id, name, age);
    }
}

测试类:

import java.util.HashSet;
public class Demo7 {
    public static void main(String[] args) {
        HashSet<Student> set = new HashSet<>();
        Student stu = new Student("0001","张三",20);
//        set.add(new Student("0001","张三",20));//没重写时相同的人不会去重,因为new出的内存地址不同
//        set.add(new Student("0001","张三",20));
        set.add(stu);
        set.add(stu);//去重
        System.out.println(set.size());
        set.add(new Student("0002","李四",22));
        set.add(new Student("0002","李四",22));//相同成功去重,在Student类下重写hashCode()和equals()方法了
        for (Student i: set) {
            System.out.println("姓名:"+i.getName());
        }
    }
}

TreeSet(重点,常用)(无下标、有序、数据不可重复(去重))

有序及去重原理:

TreeSet底层Map实现,去重和排序是比较器实现

TreeSet底层排序的二叉树的遍历是按照升序的结果出现的,这个升序是靠中序遍历得到的,相等不存,小存左,大存右

  1. 当TreeSet集合调用add()方法,比较器compareTo()会对添加进来的元素进行比较

    ? 返回值为0,不允许添加

    ? 返回值为正数,添加至右子树

    ? 返回值为负数,添加至左子树

  2. 二期项目需要对某个自定义临时进行比较,意味着要改源码,可通过外部比较器

    ? 比较器:为了服务TreeSet,目的是去重和比较
    ? 内部比较器:直接让自定义类实现Comparable接口的compareTo()方法
    ? 外部比较器:优先级高于内部比较器,独立于自定义类的,需创建新的类实现Comparator<自定义类>接口的compare(对象1,对象2)方法

注意:
  1. 如果使用TreeSet存储系统类型对象,可以直接使用
  2. 如果使用TreeSet存储自定义类型对象,需要该类实现Comparable接口的compareTo(对象)方法创建新的类实现Comparator<自定义类>接口的compare(对象1,对象2)方法

创建对象:TreeSet<引用数据类型> set = new TreeSet<>();

TreeSet遍历方式和HashSet遍历方式一样,看上面Set遍历


内部比较器写法:要会编写Comparable的compareTo方法实现排序

import java.util.TreeSet;
public class Demo8 {
    public static void main(String[] args) {
        TreeSet<Student> set = new TreeSet<>();//没有下标,数据不可重复,有排序功能
        //set.add(new Student("0001","张三",20));//会报错,提示Student类不可转换成Comparable比较器,要在Student类实现接口的compareTo方法
        set.add(new Student("0001","张三",20));
        set.add(new Student("0001","张三",20));
        set.add(new Student("0002","李四",25));
        set.add(new Student("0003","王五",18));
        set.add(new Student("0004","老六",30));
        for (Student i: set) {
            System.out.println("姓名:"+i.getName()+"\t年龄:"+ i.getAge());
        }
        String str = new String("abcdefg");
        String str1 = new String("bbc");
        System.out.println(str.compareTo(str1));
        }
    }
}
import java.util.Objects;
public class Student implements Comparable{//比较器接口,TreeSet用的
    private String id;
    private String name;
    private int age;

    public Student(String id, String name, int age) {
        this.id = id;
        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;
    }
    public String getId() {
        return id;
    }
    public void setId(String id) {
        this.id = id;
    }
    @Override
    public int compareTo(Object o) {
        //要自己写,比较此对象与指定对象的顺序,返回0相等,返回正数放在右子树,返回负数放在左子树
//TreeSet底层的二叉树的遍历是按照升序的结果出现的,这个升序是靠中序遍历得到的,相等不存,小存左,大存右
        if (this == o){//地址相同
            return 0;
        }
        if (o instanceof Student){//判断o是不是Student类型
            Student student = (Student) o;//向下转型
            if (this.id.equals(student.id)){//学生ID相同
                return 0;
            }else if(this.age > student.age){//按年龄排序
                return 1;//放在右子树
            }else {
                return -1;//放在左子树
            }
        }
        return 0;
    }
}

外部比较器写法:要会编写Comparator的compare方法实现排序

public class Demo8 {
    public static void main(String[] args) {
        TreeSet<Student> set1 = new TreeSet<>(new StudentCmp());//外部比较器,注意这里
        set1.add(new Student("0001","张三",20));
        set1.add(new Student("0001","张三",20));
        set1.add(new Student("0002","李四",25));
        set1.add(new Student("1111","王五",18));
        set1.add(new Student("0004","老六",18));
        for (Student i: set1) {
            System.out.println("ID:"+i.getId()+"\t姓名:"+i.getName()+"\t年龄:"+ i.getAge());
        }
    }
}
public class Student{
    private String id;
    private String name;
    private int age;
    public Student(String id, String name, int age) {
        this.id = id;
        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;
    }
    public String getId() {
        return id;
    }
    public void setId(String id) {
        this.id = id;
    }
}
import java.util.Comparator;

public class StudentCmp implements Comparator<Student> {

    public int compare(Student o1, Student o2) {
        if (o1.getId().equals(o2.getId())){//学号相等返回0,相等
            return 0;
        }else if(o1.getAge() > o2.getAge()){//按年龄排序,从大到小,当前对象o1大于o2就把o1放左子树先输出
            return -1;//放在左子树
        }else if(o1.getAge() < o2.getAge()){
            return 1;//放在右子树
        }else {//年龄相等比较ID小的放前
            return o1.getId().compareTo(o2.getId());//ID进行比较
        }
    }
}

Map接口(重点)(没有迭代器)

通过实现类创建对象:Map map = new HashMap();//不能用子类特有的方法

注意:
  1. key一般放基本数据类型的包装类,value存放各种引用数据类型
  2. key在TreeMap是有序的,HashMap是无序的,数据不可重复,value是无序的,数据可重复
HashMap、TreeMap常用方法说明返回值用法
put(Object key,Object value)将指定key-value添加到(或修改)当前map对象中Object添加
clear()清空当前map中的所有数据void清除
remove(Object key)移除指定key的键值对,并返回valueObject删除
get(Object key)获取指定key对应的valueObject查询
size()返回map中key-value对的个数int长度
isEmpty()判断当前map是否为空boolean判空
equals(Object obj)判断当前map和参数对象obj是否相等boolean判等
putAll(Map m)将m中的所有key-value对存放到当前map中void拷贝
containsKey(Object key)是否包含指定的keyboolean找key
containsValue(Object value)是否包含指定的valueboolean找value
keySet()返回所有key构成的Set集合Set遍历
values()返回所有value构成的Collection集合Collection遍历
entrySet()返回所有key-value对构成的Set集Set遍历

HashMap、TreeMap的三种遍历方式(重点,必须背下来)

由于Map没有迭代器,遍历需要通过下面三个方法生成Set和Collection集合进行遍历

同样可用、省内存的迭代器方式和增强for循环

方法说明使用方法:需创建HashMap或TreeMap对象设置泛型后
keySet()获得map集合中,所有的keySet<key类型> keySet = 对象.keySet();//得到所有key的set集合
Iterator<key类型> iterator = keySet.iterator();
while (iterator.hasNext()){
key类型 next = iterator.next();
System.out.println(“key:”+next+“value:”+对象.get(next));
}
values()获得map集合中,所有的valueCollection<value类型> values = map.values();
Iterator<value类型> iterator = values.iterator();
while (iterator.hasNext()){
value类型 next = iterator.next();
System.out.println(“value的值:”+next);
}
entrySet()获得map集合中,key+valueSet<Map.Entry<key类型, value类型>> entries = map.entrySet();
Iterator<Map.Entry<key类型, value类型>> iterator = entries.iterator();
while (iterator.hasNext()){
Map.Entry<key类型, value类型> next = iterator.next();
System.out.println(“key:”+next.getKey()+“value:”+next.getValue());
}
其他方法遍历代码:
Iterator迭代器看上面
迭代器省内存for(Iterator<key类型> it = map.keySet().iterator();it.hasNext(); ){
key类型 next = it.next();
System.out.println(“key:”+next+“value:”+map.get(next));
}
for(Iterator<value类型> it = map.values().iterator();it.hasNext(); ){
value类型 next = it.next();
System.out.println(“value:”+next);
}
for(Iterator<Map.Entry<key类型, value类型>> it = map.entrySet().iterator();it.hasNext(); ){
Map.Entry<key类型, value类型> next = it.next();
System.out.println(“key:”+next.getKey()+“value:”+next.getValue());
}
forEach方式
快捷键.for
for (key类型 key1 : map.keySet()) {
System.out.println(“key:”+key1+“value:”+map.get(key1));
}
for (value类型 value1 : map.values()) {
System.out.println(“value:”+value1);
}
for (Map.Entry<key类型, value类型> next : map.entrySet()) {
System.out.println(“key:”+next.getKey()+“value:”+next.getValue());
}
for循环Collection<value类型> values = map.values();
Object[] array = values.toArray();
for (int i = 0; i < array.length; i++) {
System.out.println("value:"array[i]);
}

可通过map对象.上面的方法.var快捷生成Set和Collection对象

在这里插入图片描述

再在循环内获取集合中的单个对象都可通过IDEA的.var快捷生成对象

在这里插入图片描述

可看下面代码理解`

HashMap(偏重点,会用即可)(都无序、key不可重复(去重))

创建对象:HashMap<key类型, value类型> map = new HashMap<>();

import java.util.*;
public class Demo9 {
    public static void main(String[] args) {
        HashMap<Integer,String> map = new HashMap<>();
        map.put(1,"张三");
        map.put(1,"李四");//会覆盖原来key对应的数据
        map.put(2,"王五");
        map.put(3,"老六");
        map.put(9,"小七");
        map.put(0,"大八");
        System.out.println(map.remove(4));
        System.out.println(map);
        //由于没有迭代器,使用3种遍历Map集合的方式:【面试常考】【迭代器还可细分10种】
        //【方式一】
        Set<Integer> keySet = map.keySet();//得到所有key的set集合
        Iterator<Integer> iterator = keySet.iterator();
        while (iterator.hasNext()){
            Integer next = iterator.next();
            System.out.println("key的值是:"+next+"\tvalue值是:"+map.get(next));
        }
        //【方式二】
        Collection<String> values = map.values();
        Iterator<String> iterator1 = values.iterator();
        while (iterator1.hasNext()){
            String next = iterator1.next();
            System.out.println("【方式三】value的值:"+next);
        }
        //【方式三】
        Set<Map.Entry<Integer, String>> entries = map.entrySet();
        Iterator<Map.Entry<Integer, String>> iterator2 = entries.iterator();
        while (iterator2.hasNext()){
            Map.Entry<Integer, String> next = iterator2.next();
            System.out.println("【方式三】key的值:"+next.getKey()+"\tvalue的值:"+next.getValue());
        }
        //【自己扩展方法】
        System.out.println("=============================");
        //省内存迭代器方式
        for(Iterator<Integer> it = map.keySet().iterator();it.hasNext();){
            Integer next = it.next();
            System.out.println("key:"+next+"value:"+map.get(next));
        }
        for(Iterator<String> it = map.values().iterator();it.hasNext();){
            String next = it.next();
            System.out.println("value:"+next);
        }
        for(Iterator<Map.Entry<Integer, String>> it = map.entrySet().iterator();it.hasNext();){
            Map.Entry<Integer, String> next = it.next();
            System.out.println("key:"+next.getKey()+"value:"+next.getValue());
        }
        //for循环,只能map.values()
        Collection<String> values1 = map.values();
        Object[] array = values1.toArray();
        for (int i = 0; i < array.length; i++) {
            System.out.println("value:"+array[i]);
        }
        //foreach方式
        for (Integer key : map.keySet()) {
            System.out.println("key:"+key+"value:"+map.get(key));
        }
        for (String value : map.values()) {
            System.out.println("value:"+value);
        }
        for (Map.Entry<Integer, String> next : map.entrySet()) {
            System.out.println("key:"+next.getKey()+"value:"+next.getValue());
        }
    }
}

TreeMap(偏重点,会用即可)(key有序value无序、key不可重复(去重))

创建对象:TreeMap<key类型, value类型> map = new TreeMap<>();

(1)内部比较器:

import java.util.Map;
import java.util.TreeMap;
public class Test03 {
    public static void main(String[] args) {
        Map<Student,Integer> map = new TreeMap<>();
        map.put(new Student(19,"blili",170.5),1001);
        map.put(new Student(18,"blili",150.5),1003);
        map.put(new Student(19,"alili",180.5),1023);
        map.put(new Student(17,"clili",140.5),1671);
        map.put(new Student(10,"dlili",160.5),1891);
        System.out.println(map);
        System.out.println(map.size());
    }
}
public class Student implements Comparable<Student>{
    private int age;
    private String name;
    private double height;
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public double getHeight() {
        return height;
    }
    public void setHeight(double height) {
        this.height = height;
    }
    public Student(int age, String name, double height) {
        this.age = age;
        this.name = name;
        this.height = height;
    }
    @Override
    public String toString() {
        return "Student{" +
                "age=" + age +
                ", name='" + name + '\'' +
                ", height=" + height +
                '}';
    }
    @Override
    public int compareTo(Student o) {
       /* return this.getAge()-o.getAge();*/
        return this.getName().compareTo(o.getName());
    }
}

(2)外部比较器:

import java.util.Comparator;
import java.util.Map;
import java.util.TreeMap;
public class Test03 {
    public static void main(String[] args) {
        Map<Student,Integer> map = new TreeMap<>(new Comparator<Student>() {
            @Override
            public int compare(Student o1, Student o2) {
                return ((Double)(o1.getHeight())).compareTo((Double)(o2.getHeight()));
            }
        });
        map.put(new Student(19,"blili",170.5),1001);
        map.put(new Student(18,"blili",150.5),1003);
        map.put(new Student(19,"alili",180.5),1023);
        map.put(new Student(17,"clili",140.5),1671);
        map.put(new Student(10,"dlili",160.5),1891);
        System.out.println(map);
        System.out.println(map.size());
    }
}

Collections工具类(了解)

import java.util.ArrayList;
import java.util.Collections;
public class Test01 {
    //这是main方法,程序的入口
    public static void main(String[] args) {
        //Collections不支持创建对象,因为构造器私有化了
        /*Collections cols = new Collections();*/
        //里面的属性和方法都是被static修饰,我们可以直接用类名.去调用即可:
        //常用方法:
        //addAll:
        ArrayList<String> list = new ArrayList<>();
        list.add("cc");
        list.add("bb");
        list.add("aa");
        Collections.addAll(list,"ee","dd","ff");
        Collections.addAll(list,new String[]{"gg","oo","pp"});
        System.out.println(list);
        //binarySearch必须在有序的集合中查找:--》排序:
        Collections.sort(list);//sort提供的是升序排列
        System.out.println(list);
        //binarySearch
        System.out.println(Collections.binarySearch(list, "cc"));

        //copy:替换方法
        ArrayList<String> list2 = new ArrayList<>();
        Collections.addAll(list2,"tt","ss");
        Collections.copy(list,list2);//将list2的内容替换到list上去
        System.out.println(list);
        System.out.println(list2);

        //fill 填充
        Collections.fill(list2,"yyy");
        System.out.println(list2);
    }
}
方法名说明返回值
Collections.addAll(集合,[数组][.数据]…)集合后添加数据boolean
Collections.sort(集合)集合升序排序void
Collections.binarySearch(集合,数据)二分查找,返回下标int
Collections.copy(集合1,集合2)集合2对应位置的内容替换到集合1对应位置中,其他不变void
fill(集合,数据)整个集合填充成指定内容void

通配符(了解,一般就源代码用)

【1】在没有通配符的时候:

下面的a方法,相当于方法的重复定义,报错

public class Test {
    /*public void a(List<Object> list){

    }
    public void a(List<String> list){

    }
    public void a(List<Integer> list){

    }*/
}

【2】引入通配符:

public class Demo {
    //这是main方法,程序的入口
    public static void main(String[] args) {
        List<Object> list1 = new ArrayList<>();
        List<String> list2 = new ArrayList<>();
        List<Integer> list3 = new ArrayList<>();

        List<?> list = null;
        list = list1;
        list = list2;
        list = list3;
    }
}

发现: A 和 B是子类父类的关系,G<A>和G<B>不存在子类父类关系,是并列的

加入通配符?后,G<?>就变成了 G<A>和G<B>的父类

【3】使用通配符:

import java.util.ArrayList;
import java.util.List;
public class Test {
    /*public void a(List<Object> list){

    }
    public void a(List<String> list){

    }
    public void a(List<Integer> list){

    }*/
    public void a(List<?> list){
        //内部遍历的时候用Object即可,不用?
        for(Object a:list){
            System.out.println(a);
        }
    }
}

class T{
    //这是main方法,程序的入口
    public static void main(String[] args) {
        Test t = new Test();
        t.a(new ArrayList<Integer>());
        t.a(new ArrayList<String>());
        t.a(new ArrayList<Object>());
    }
}

E.使用通配符后的细节

public class Test {
    public void a(List<?> list){
        //1.遍历:
        for(Object a:list){
            System.out.println(a);
        }
        //2.数据的写入操作 :
        //list.add("abc");-->出错,不能随意的添加数据
        list.add(null);
        //3.数据的读取操作:
        Object s = list.get(0);
    }
}

class T{
    //这是main方法,程序的入口
    public static void main(String[] args) {
        Test t = new Test();
        t.a(new ArrayList<Integer>());
        t.a(new ArrayList<String>());
        t.a(new ArrayList<Object>());
    }
}

F.泛型受限,所以很少用了

import java.util.ArrayList;
import java.util.List;
public class Test {
    //这是main方法,程序的入口
    public static void main(String[] args) {
        //a,b,c三个集合是并列的关系:
        List<Object> a = new ArrayList<>();
        List<Person> b = new ArrayList<>();
        List<Student> c = new ArrayList<>();

        /*开始使用泛型受限:泛型的上限
        List<? extends Person>:
        就相当于:
        List<? extends Person>是List<Person>的父类,是List<Person的子类>的父类
         */

        List<? extends Person> list1 = null;
        /*list1 = a;
        list1 = b;
        list1 = c;*/
        /*开始使用泛型受限:泛型的下限
        List<? super Person>
        就相当于:
        List<? super Person>是List<Person>的父类,是List<Person的父类>的父类
         */
        List<? super Person> list2 = null;
        list2 = a;
        list2 = b;
        list3 = c;
    }
}

面试题(重点)

Java集合体系结构(List、Set、Collection、Map的区别和联系)

在这里插入图片描述

Collection 接口存储一组不唯一,无序的对象

List 接口存储一组不唯一,有序(插入顺序)的对象

Set 接口存储一组唯一,无序的对象

Map接口存储一组键值对象,提供key到value的映射。Key无序,唯一。value不要求有序,允许重复。(如果只使用key存储,而不使用value,那就是Set)

Vector和ArrayList的区别和联系

Vector和ArrayList的区别和联系

实现原理相同,功能相同,都是长度可变的数组结构,很多情况下可以互用

两者的主要区别如下

  1. Vector是早期JDK接口,ArrayList是替代Vector的新接口
  2. Vector线程安全,ArrayList重速度轻安全,线程非安全
  3. 长度需增长时,Vector默认增长一倍,ArrayList增长50%
ArrayList和LinkedList的区别和联系

两者都实现了List接口,都具有List中元素有序、不唯一的特点。

ArrayList实现了长度可变的数组,在内存中分配连续空间。遍历元素随机访问元素的效率比较高;

在这里插入图片描述

LinkedList采用链表存储方式。插入、删除元素时效率比较高

在这里插入图片描述

集合和数组的比较(为什么引入集合)

数组不是面向对象的,存在明显的缺陷,集合完全弥补了数组的一些缺点,比数组更灵活更实用,可大大提高软件的开发效率而且不同的集合框架类可适用于不同场合。具体如下:

  1. 数组的效率高于集合类.
  2. 数组能存放基本数据类型和对象,而集合类中只能放对象。
  3. 数组容量固定且无法动态改变,集合类容量动态改变。
  4. 数组无法判断其中实际存有多少元素,length只告诉了array的容量。
  5. 集合有多种实现方式和不同的适用场合,而不像数组仅采用顺序表方式。
  6. 集合以类的形式存在,具有封装、继承、多态等类的特性,通过简单的方法和属性调用即可实现各种复杂操作,大大提高软件的开发效率。
文章来源:https://blog.csdn.net/huichangzhe/article/details/135562922
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。