Java SE 集合(容器)

Java SE 集合(容器)

1、容器的作用和概览

  • 变量:存储单个数据的空间
  • 数组[ ]: 存储若干个相同类型数据的集合|容器
      长度不可改变
      存储的数据类型要求相同
      有序,有索引 0~length-1
    可以存储任意类型的数据
  • 集合:容器
    长度根据数据的多少动态的伸缩
    只能存储引用数据类型
  • 学习集合的重点:
    ArrayList
    HashMap

2、容器接口

  • Collection接口:集合层次结构中的根接口。 集合表示一组对象,称为其元素 。
    • List作为有序的Collection。List接口下有两个实现类 LinkedList 和 ArrayList
    • **Set接口(无序的)**下有一个 HashSet 实现类,HashSet的底层是用 HashMap 实现的。
    • 迭代器**(Iterator)**
  • Map接口
    • HashMap作为Map的实现类。
			//1.一个集合对象
        ArrayList ls = new ArrayList();
        //2.储存数据
        ls.add("哈哈");
        ls.add(false);
        ls.add(123);
        ls.add('c');
        ls.add(new int[]{1,2,3});

        System.out.println(ls);

        ls.add("hehe");
        System.out.println(ls);

        ls.remove("哈哈");
        System.out.println(ls);
        System.out.println(ls.size());

3、Collection接口

Collection接口常用方法:

  • 添加 add() addAll(Collection<> c)
  • 删除 remove() removeAll(Collection<> c)
  • 记数 size()
  • 包含 contains() contains((Collection<> c))
  • 清空 clear()
  • 是否空 isEmpty()
  • iterator() -->返回此集合中元素的迭代器。
  • Object[] toArray() 返回包含此集合中所有元素的数组。
			//集合对象
        //接口多态: 引用col只能调用Collection中存在的功能
        Collection col = new ArrayList();
        Collection col2 = new ArrayList();
        Collection col3 = new ArrayList();

        // //常用方法
        //boolean add(E e) 确保此集合包含指定的元素(可选操作)。
        col.add("gdgvdhnkjs");
        col.add(123);
        col.add('a');
        col.add(false);
        col2.add("hei");
        col2.add(124);
        col2.add('a');
        col2.add(true);
        col3.add('c');
        col3.add('b');
        col3.add('d');
        boolean addAll(Collection<? extends E> c) 将指定集合中的所有元素添加到此集合中(可选操作)。
        col.addAll(col2);
        col.addAll(col3);
        //col.add(col2); //将对象当做元素存入集合中
        System.out.println(col);

        //void clear() 从此集合中删除所有元素(可选操作)。
        col3.clear();

        //boolean isEmpty() 如果此集合不包含任何元素,则返回 true 。
        System.out.println(col.isEmpty());

        //boolean contains(Object o) 如果此collection包含指定的元素,则返回 true 。
        //boolean containsAll(Collection<?> c) 如果此集合包含指定集合中的所有元素,则返回 true 。
        System.out.println(col.contains("abc"));//false
        System.out.println(col.containsAll(col2));//true

        //boolean equals(Object o) 将指定对象与此集合进行比较以获得相等性。
        col3.addAll(col2);
        System.out.println(col2.equals(col3));  //true

        //boolean remove(Object o) 从此集合中移除指定元素的单个实例(如果存在)(可选操作)。
        System.out.println(col.remove('a'));
        System.out.println(col);
        System.out.println(col2);

        //boolean removeAll(Collection<?> c) 删除此集合的所有元素,这些元素也包含在指定的集合中(删除交集)。
        //System.out.println(col.removeAll(col2));
        System.out.println(col);
        System.out.println(col2);

        //boolean retainAll(Collection<?> c) 仅保留此集合中包含在指定集合中的元素(保留交集)。
        System.out.println(col.retainAll(col2));
        System.out.println(col);
        System.out.println(col2);

        //Object[] toArray() 返回包含此集合中所有元素的数组。
        Object[] arr = col.toArray();
        System.out.println(Arrays.toString(arr));

        //遍历方式
        //1.增强for
        for(Object obj:col){
            System.out.println(obj);
        }

        //2.迭代器
        //Iterator<E> iterator() 返回此集合中元素的迭代器。
        //1) 获取迭代器对象(获取遍历当前集合的迭代器对象)
        Iterator it  = col.iterator();

        //2) 判断是否存在下一个元素
        while(it.hasNext()){
            //3) 获取下一个元素
            System.out.println(it.next());
        }

练习

/*
    手写容器(简易版)

    定义一个存储字符串的容器类型,可以存任意个数的字符串,集合的大小可以跟随数据的多少进行增删

    尝试实现:
        根据索引删除数据
        根据索引修改数据
        根据索引查询数据
 */
public class CollectionApp01 {
    public static void main(String[] args) {
        //创建一个容器对象
        MyContainer my = new MyContainer();

        //存储数据
        my.add("zhangsan");
        System.out.println(my.size());
        System.out.println(my);
        my.add("lisi");
        System.out.println(my.size());
        System.out.println(my);
        my.add("wangwu");
        System.out.println(my.size());
        System.out.println(my);

        my.update(1,"haha");

        System.out.println(my);
        my.remove(1);
        System.out.println(my);
        System.out.println(my.size());

    }
}


//自定义容器类
class MyContainer{
    //内部存储数据的数组结构
    private String[] arr;
    //记录容器中存储的数据个数
    private int size;

    public MyContainer(){}


    /**
     * 添加数据
     * @param value 要添加的数据
     */
    public void add(String value) {
        //第一次添加
        if(arr==null || size==0){
            //创建新数组
            arr = new String[1];
            arr[0] = value;
        }else{
            //备份原数组的地址
            String[] temp = arr;
            //创建新数组 原有长度基础之上+1
            arr = new String[size+1];
            //遍历原数组数据全部一次拷贝到新数组中
            //i作为原数组与新数组的索引
            for(int i=0;i<size;i++){
                arr[i] = temp[i];
            }

            //value添加 到新数组 的最后
            arr[size] = value;
        }
        //长度+1
        size++;
    }

    /**根据据索引修改数据
     *
     * @param index 索引
     * @param value 新的值
     * @return 被修改的值
     */
    public String update(int index, String value) {
        //校验索引
        if(index<0 || index>=size){
            throw new ContainerIndexOutOfBoundsException(index);
        }
        //原数据
        String s = arr[index];
        arr[index] = value;
        return s;
    }

    /**
     * 根据索引删除数据
     * index : 索引
     */
    public void remove(int index){
        //校验索引
        if(index<0 || index>=size){
            throw new ContainerIndexOutOfBoundsException(index);
        }

        //1.备份原数组
        String[] temp = arr;

        //2.创建新数组
        arr = new String[size-1];

        //3.数组内容的拷贝
        //i作为原数组的索引
        for(int i=0;i<size;i++){
            if(i<index){
                arr[i] = temp[i];
            }else if(i>index){
                arr[i-1] = temp[i];
            }
        }

        //4.长度-1
        size--;
    }


    //获取容器中数据的个数
    public int size(){
        return this.size;
    }

    @Override
    public String toString() {
        return Arrays.toString(arr);
    }


}

//自定义异常  容器索引越界异常
class ContainerIndexOutOfBoundsException extends IndexOutOfBoundsException{
    public ContainerIndexOutOfBoundsException() {
        super();
    }
    public ContainerIndexOutOfBoundsException(String s) {
        super(s);
    }

    public ContainerIndexOutOfBoundsException(int index) {
        super("Container index out of range: " + index);
    }

}

3.1 、List 接口

  • Interface List< E >

  • 有序可重复(也称为序列 )。

  • 新增了提供一些可以根据索引操作的方法

  • 泛型的作用 : 提高安全性,规范性 达到类型检查的作用
    数据类型<执行规范的数据类型> 规定集合中所有存储数据的数据类型

常用方法:

变量和类型方法描述
voidadd(int index, E element)将指定元素插入此列表中的指定位置(可选操作)。
booleanadd(E e)将指定的元素追加到此列表的末尾(可选操作)。
booleanaddAll(int index, Collection<? extends E> c)将指定集合中的所有元素插入到指定位置的此列表中(可选操作)。
booleanaddAll(Collection<? extends E> c)将指定集合中的所有元素按指定集合的迭代器(可选操作)返回的顺序追加到此列表的末尾。
voidclear()从此列表中删除所有元素(可选操作)。
booleancontains(Object o)如果此列表包含指定的元素,则返回 true
booleancontainsAll(Collection<?> c)如果此列表包含指定集合的所有元素,则返回 true
static < E > List< E >copyOf(Collection<? extends E> coll)以迭代顺序返回包含给定Collection的元素的 unmodifiable List
booleanequals(Object o)将指定对象与此列表进行比较以获得相等性。
Eget(int index)返回此列表中指定位置的元素。
intindexOf(Object o)返回此列表中第一次出现的指定元素的索引,如果此列表不包含该元素,则返回-1。
intlastIndexOf(Object o)返回此列表中指定元素最后一次出现的索引,如果此列表不包含该元素,则返回-1。
Iterator< E >iterator()以适当的顺序返回此列表中元素的迭代器。
booleanisEmpty()如果此列表不包含任何元素,则返回 true 。
ListIterator< E >listIterator()返回此列表中元素的列表迭代器(按适当顺序)。
ListIterator< E >listIterator(int index)从列表中的指定位置开始,返回列表中元素的列表迭代器(按正确顺序)。
static < E > List< E >of()返回包含零元素的不可修改列表。
static < E > List< E >of(E e1)返回包含一个元素的不可修改列表。
static < E > List< E >of(E… elements)返回包含任意数量元素的不可修改列表。
static < E > List< E >of(E e1, E e2)返回包含两个元素的不可修改列表。
Eremove(int index)删除此列表中指定位置的元素(可选操作)。
booleanremove(Object o)从该列表中删除指定元素的第一个匹配项(如果存在)(可选操作)。
booleanremoveAll(Collection<?> c)从此列表中删除指定集合中包含的所有元素**(删除交集)。**
booleanretainAll(Collection<?> c)仅保留此列表中包含在指定集合中的元素**(保留交集)**。
Eset(int index, E element)用指定的元素替换此列表中指定位置的元素(可选操作)。
intsize()返回此列表中的元素数。
ListsubList(int fromIndex, int toIndex)返回指定的 fromIndex (包含)和 toIndex (不包括)之间的此列表部分的视图。
Object[]toArray()以适当的顺序(从第一个元素到最后一个元素)返回包含此列表中所有元素的数组。
T[]toArray(T[] a)以适当的顺序返回包含此列表中所有元素的数组(从第一个元素到最后一个元素); 返回数组的运行时类型是指定数组的运行时类型。
//泛型的作用 : 提高安全性,规范性  达到类型检查的作用
        //数据类型<执行规范的数据类型> 规定集合中所有存储数据的数据类型
        Collection col = new ArrayList(); //存储任意类型 的数据
        List<String> list = new ArrayList<String>(); //存储String类型的数据

        /*
        void add(int index, E element) 将指定元素插入此列表中的指定位置(可选操作)。
        boolean add(E e) 将指定的元素追加到此列表的末尾(可选操作)。
        boolean addAll(int index, Collection<? extends E> c) 将指定集合中的所有元素插入到指定位置的此列表中(可选操作)。
        boolean addAll(Collection<? extends E> c) 将指定集合中的所有元素按指定集合的迭代器(可选操作)返回的顺序追加到此列表的末尾。
         */
        list.add("lisi");
        list.add("zhangsan");
        list.add("wangwu");
        list.add("zhaoliu");

        list.add(1,"zhaoliu");
        //list.add(6,"zhaoliu");
        System.out.println(list);

        col.add("wangwu");
        col.add("zhaoliu");

        //static <E> List<E> copyOf(Collection<? extends E> coll)  拷贝
        List ls = List.copyOf(list);
        System.out.println(ls);
        System.out.println(ls==list);

        //boolean contains(Object o) 如果此列表包含指定的元素,则返回 true 。
        //boolean containsAll(Collection<?> c) 如果此列表包含指定集合的所有元素,则返回 true 。
        System.out.println(ls.contains("zhangsan"));

        System.out.println(list.containsAll(col));

        //E get(int index) 返回此列表中指定位置的元素。
        System.out.println(list.get(2));

        //int indexOf(Object o) 返回此列表中第一次出现的指定元素的索引,如果此列表不包含该元素,则返回-1。
        System.out.println(list.indexOf("zhaoliu"));
        System.out.println(list.lastIndexOf("zhaoliu"));

        //static <E> List<E> of(E... elements) 返回包含任意数量元素的不可修改列表。  不允许修改内容与长度的List列表
        List list2 = List.of(3,4,5,6,7,8,9);
        //list2.remove(3);  //以索引为主
        //list2.set(1,0);  //以索引为主
        System.out.println(list2);

        //List<E> subList(int fromIndex, int toIndex) 返回指定的 fromIndex (包含)和 toIndex (不包括)之间的此列表部分的视图。
        System.out.println(list.subList(1,3));

        //List 有序--> 根据for普通遍历,i条件作为索引
        for(int i=0;i<list.size();i++){
            System.out.println(list.get(i));
        }

        test01();
    }

    public static void test01(){
//        1.定义一个集合: 存储指定你喜欢的漫威英雄人物
//        2.如果集合中存在灭霸,就添加一个惊奇队长
//        使用各种方式进行操作
        List<String> ls=new ArrayList<String>();
        ls.add("美队");
        ls.add("钢铁侠");ls.add("黑寡妇");ls.add("绿巨人");
        ls.add("雷神");
        ls.add("蜘蛛侠");
        ls.add("蚁人");ls.add("鹰眼");ls.add("绯红");

        if(ls.contains("灭霸")){
            ls.add("惊奇队长");
        }
        System.out.println(ls);
        ls.add("灭霸");
    //z专用ListIterator 迭代器
        ListIterator<String> lit= ls.listIterator();
        while(lit.hasNext()){
            if("灭霸".equals(lit.next())){
                lit.add("惊奇队长");
            }
        }
        System.out.println(ls);
        //反向遍历。
        while(lit.hasPrevious()){
            if("灭霸".equals(lit.previous())){
                lit.add("惊奇队长");
            }
        }
        System.out.println(ls);
}

3.1.1、ArrayList 类

  • 底层结构: 可变数组

  • 优点: 根据索引查询,修改效率高

  • 缺点: 做增加,删除效率低

  • 应用场景: 大量做查询,少量做增删的时候适合使用ArrayList

  • 扩容机制: int newCapacity = oldCapacity + (oldCapacity >> 1);
    每次扩容原容量的1.5倍

  • 同步: 线程不安全的|不同步的

Vector 向量

  • 内部也是通过数组存储数据
  • 与ArrayList特点相同
  • 不同:1)线程安全的|同步的
    2)**Vector每次扩容原容量的2倍,**ArrayList每次扩容原容量1.5倍,ArrayList有利于节省内存空间

建议:如果不需要线程安全实现,建议使用ArrayList代替Vector

1、构造器
ArrayList()构造一个初始容量为10的空列表。
ArrayList(int initialCapacity)****构造具有指定初始容量的空列表。
ArrayList(Collection<? extends E> c)按照集合的迭代器返回的顺序构造一个包含指定集合元素的列表。
ArrayList<Integer> list = new ArrayList<>();  //构造一个初始容量为10的空列表。
//ArrayList(int initialCapacity) 构造具有指定初始容量的空列表。
// --> 建议: 当确定存储多少个数据的时候使用
 ArrayList<Integer> list2 = new ArrayList<>(20);
2、常用方法(一些)
变量和类型方法描述
voidadd(int index, E element)将指定元素插入此列表中的指定位置。
booleanadd(E e)将指定的元素追加到此列表的末尾。
booleanaddAll(int index, Collection<? extends E> c)从指定位置开始,将指定集合中的所有元素插入此列表。
voidclear()从此列表中删除所有元素。
booleancontains(Object o)如果此列表包含指定的元素,则返回 true 。
voidensureCapacity(int minCapacity)如有必要,增加此 ArrayList实例的容量,以确保它至少可以容纳由minimum capacity参数指定的元素数。
Eget(int index)返回此列表中指定位置的元素。
intindexOf(Object o)返回此列表中第一次出现的指定元素的索引,如果此列表不包含该元素,则返回-1。
Iteratoriterator()以适当的顺序返回此列表中元素的迭代器。
intlastIndexOf(Object o)返回此列表中指定元素最后一次出现的索引,如果此列表不包含该元素,则返回-1。
ListIteratorlistIterator(int index)从列表中的指定位置开始,返回列表中元素的列表迭代器(按正确顺序)。
Eremove(int index)删除此列表中指定位置的元素。
booleanremove(Object o)从该列表中删除指定元素的第一个匹配项(如果存在)。
protected voidremoveRange(int fromIndex, int toIndex)从此列表中删除索引介于 fromIndex (含)和 toIndex (独占)之间的所有元素。
booleanretainAll(Collection<?> c)仅保留此列表中包含在指定集合中的元素。
Eset(int index, E element)用指定的元素替换此列表中指定位置的元素。
intsize()返回此列表中的元素数。
ListsubList(int fromIndex, int toIndex)返回指定的 fromIndex (包含)和 toIndex (不包括)之间的此列表部分的视图。
voidforEach(Consumer<? super E>action)对 Iterable每个元素执行给定操作,直到处理 Iterable所有元素或操作引发异常。
ArrayList<Integer> list = new ArrayList<>();  //构造一个初始容量为10的空列表。
        //ArrayList(int initialCapacity) 构造具有指定初始容量的空列表。 --> 建议: 当确定存储多少个数据的时候使用
        ArrayList<Integer> list2 = new ArrayList<>(20);
        ArrayList<Integer> list3 = new ArrayList<>();
        list3.add(123);

        list.add(123);
        list.add(456);
        list.add(789);
        System.out.println(list);

        //void add(int index, E element) 将指定元素插入此列表中的指定位置。
        //boolean add(E e) 将指定的元素追加到此列表的末尾。
        //boolean addAll(int index, Collection<? extends E> c) 从指定位置开始,将指定集合中的所有元素插入此列表。
        //boolean addAll(Collection<? extends E> c) 将指定集合中的所有元素按指定集合的Iterator返回的顺序附加到此列表的末尾。
        list.add(0,123);
        list.add(54645);
        list2.addAll(list);

        //void clear() 从此列表中删除所有元素。
        list2.clear();
        //Object clone() 返回此 ArrayList实例的浅表副本。
        Object o=list.clone();
        //boolean contains(Object o) 如果此列表包含指定的元素,则返回 true 。
        System.out.println(list.contains(123));
        //void ensureCapacity(int minCapacity) 如有必要,增加此 ArrayList实例的容量,以确保它至少可以容纳由minimum capacity参数指定的元素数。

        //void forEach(Consumer<? super E> action) 对 Iterable每个元素执行给定操作,直到处理 Iterable所有元素或操作引发异常。

        //E get(int index) 返回此列表中指定位置的元素。
        System.out.println(list.get(1));
        //int indexOf(Object o) 返回此列表中第一次出现的指定元素的索引,如果此列表不包含该元素,则返回-1。
        System.out.println(list.indexOf(123));
        //int lastIndexOf(Object o) 返回此列表中指定元素最后一次出现的索引,如果此列表不包含该元素,则返回-1。
        System.out.println(list.lastIndexOf(123));

        //boolean isEmpty() 如果此列表不包含任何元素,则返回 true 。
        System.out.println(list.isEmpty());
        //Iterator<E> iterator() 以适当的顺序返回此列表中元素的迭代器。
        Iterator it=list.iterator();
        //ListIterator<E> listIterator() 返回此列表中元素的列表迭代器(按适当顺序)。
        ListIterator listIterator=list.listIterator();
        //ListIterator<E> listIterator(int index) 从列表中的指定位置开始,返回列表中元素的列表迭代器(按正确顺序)。
        ListIterator listIterator2=list.listIterator(1);

        //E remove(int index) 删除此列表中指定位置的元素。
        //boolean remove(Object o) 从该列表中删除指定元素的第一个匹配项(如果存在)。
        //boolean removeAll(Collection<?> c) 从此列表中删除指定集合中包含的所有元素。
        list.remove(123);
        //boolean removeIf(Predicate<? super E> filter) 删除此集合中满足给定谓词的所有元素。

        //boolean retainAll(Collection<?> c) 仅保留此列表中包含在指定集合中的元素。
        list.removeAll(list2);
        //E set(int index, E element) 用指定的元素替换此列表中指定位置的元素。
        list.set(1,123);
        //int size() 返回此列表中的元素数。
        list.size();

        //List<E> subList(int fromIndex, int toIndex) 返回指定的 fromIndex (包含)和 toIndex (不包括)之间的此列表部分的视图。
        list.subList(0,2);
        //Object[] toArray() 以适当的顺序(从第一个元素到最后一个元素)返回包含此列表中所有元素的数组。
        System.out.println(list.toArray());

3.1.2 LinkedList 类

  • 底层结构: 双向链表
  • 特点:
    增删效率较高
    根据索引查询,遍历,修改效率低
  • 应用场景: 在大量做增删,少量做查询的位置适合使用LinkedList
  • 新增: 新增了一些操作链表头尾的方法

练习: 使用LinkedList存储自定义引用数据类型的数据,并操作练习

1、构造器
构造器描述
LinkedList()构造一个空列表。
LinkedList(Collection<? extends E> c)按照集合的迭代器返回的顺序构造一个包含指定集合元素的列表。
 LinkedList<String> ll=new LinkedList<>();
 LinkedList<String> l2=new LinkedList<>(ll);
2、常用方法
方法描述
add(int index, E element)将指定元素插入此列表中的指定位置。
add(E e)将指定的元素追加到此列表的末尾。
addAll(int index, Collection<? extends E> c)从指定位置开始,将指定集合中的所有元素插入此列表。
addAll(Collection<? extends E> c)将指定集合中的所有元素按指定集合的迭代器返回的顺序附加到此列表的末尾。
addFirst(E e)在此列表的开头插入指定的元素。
addLast(E e)将指定的元素追加到此列表的末尾。
clear()从此列表中删除所有元素。
clone()返回此 LinkedList的浅表副本。
contains(Object o)如果此列表包含指定的元素,则返回 true 。
descendingIterator()以相反的顺序返回此双端队列中元素的迭代器。
element()检索但不删除此列表的头部(第一个元素)。
get(int index)返回此列表中指定位置的元素。
getFirst()返回此列表中的第一个元素。
getLast()返回此列表中的最后一个元素。
indexOf(Object o)返回此列表中第一次出现的指定元素的索引,如果此列表不包含该元素,则返回-1。
lastIndexOf(Object o)返回此列表中指定元素最后一次出现的索引,如果此列表不包含该元素,则返回-1。
listIterator(int index)从列表中的指定位置开始,返回此列表中元素的列表迭代器(按正确顺序)。
offer(E e)将指定的元素添加为此列表的尾部(最后一个元素)。
offerFirst(E e)在此列表的前面插入指定的元素。
offerLast(E e)在此列表的末尾插入指定的元素。
peek()检索但不删除此列表的头部(第一个元素)。
peekFirst()检索但不删除此列表的第一个元素,如果此列表为空,则返回 null 。
peekLast()检索但不删除此列表的最后一个元素,如果此列表为空,则返回 null 。
poll()检索并删除此列表的头部(第一个元素)。
pollFirst()检索并删除此列表的第一个元素,如果此列表为空,则返回 null 。
pollLast()检索并删除此列表的最后一个元素,如果此列表为空,则返回 null 。
remove()检索并删除此列表的头部(第一个元素)。
remove(int index)删除此列表中指定位置的元素。
remove(Object o)从该列表中删除指定元素的第一个匹配项(如果存在)。
removeFirst()从此列表中删除并返回第一个元素。
removeFirstOccurrence(Object o)删除此列表中第一次出现的指定元素(从头到尾遍历列表时)。
removeLast()从此列表中删除并返回最后一个元素。
removeLastOccurrence(Object o)删除此列表中最后一次出现的指定元素(从头到尾遍历列表时)。
set(int index, E element)用指定的元素替换此列表中指定位置的元素。
size()返回此列表中的元素数。
toArray()以适当的顺序(从第一个元素到最后一个元素)返回包含此列表中所有元素的数组。
toArray(T[] a)以适当的顺序返回包含此列表中所有元素的数组(从第一个元素到最后一个元素); 返回数组的运行时类型是指定数组的运行时类型。
			//boolean add(E e) 将指定的元素追加到此列表的末尾。
        ll.add("uhsufjk");
        //void addFirst(E e) 在此列表的开头插入指定的元素。
        ll.addFirst("First");
        //void addLast(E e) 将指定的元素追加到此列表的末尾。
        ll.addLast("Last");
        //E element() 检索但不删除此列表的头部(第一个元素)。
        System.out.println(ll.element());
        //boolean offerFirst(E e) 在此列表的前面插入指定的元素
        System.out.println(ll.offerFirst("first"));
        //boolean offerLast(E e) 在此列表的末尾插入指定的元素。
        System.out.println(ll.offerLast("last"));

        //E get(int index) 返回此列表中指定位置的元素。
        //E getFirst() 返回此列表中的第一个元素。
        //E getLast() 返回此列表中的最后一个元素。
        System.out.println(ll.getFirst());
        System.out.println(ll.get(1));

        //int indexOf(Object o) 返回此列表中第一次出现的指定元素的索引,如果此列表不包含该元素,则返回-1。
        //int lastIndexOf(Object o) 返回此列表中指定元素最后一次出现的索引,如果此列表不包含该元素,则返回-1。
        System.out.println(ll.indexOf("uhsufjk"));
        System.out.println(ll.lastIndexOf("uhsufjk"));

        //E peek() 检索但不删除此列表的头部(第一个元素)。
        //E peekFirst() 检索但不删除此列表的第一个元素,如果此列表为空,则返回 null 。
        //E peekLast() 检索但不删除此列表的最后一个元素,如果此列表为空,则返回 null 。
        System.out.println(ll.peek());
        System.out.println(ll.peekLast());
        //E poll() 检索并删除此列表的头部(第一个元素)。
        //E pollFirst() 检索并删除此列表的第一个元素,如果此列表为空,则返回 null 。
        //E pollLast() 检索并删除此列表的最后一个元素,如果此列表为空,则返回 null 。
        System.out.println(ll.pollFirst());
3、手写 Linkedlist单向链表
/*
    手写LinkedList
        使用单向链表实现

        思考实现:
            根据索引修改,查询
 */
public class MyLinkedListDemo02 {
    public static void main(String[] args) {
        MyLinkedList list = new MyLinkedList();

        //list.add("数据");
        System.out.println(list.size());
        //list.add("haha");
        System.out.println(list.size());
        System.out.println(list);
    }
}

//自定义容器类型: MyLinkedList
class MyLinkedList{
    //链表头节点
    private Node head;
    //长度
    private int size;

    public MyLinkedList() {
    }

    /*
        添加
     */
    public void add(Object value) {
        //创建新节点
        Node node = new Node(value,null);
        //判断是不否存在链表头节点
        if(head==null && size==0){
            head = node;  //新节点就是链表头节点
        }else{
            //存在原链表,遍历原链表,找到最后一个节点,新节点的地址记录
            Node temp = head;  //temp指向链表头节点,后面使用temp操作遍历指向每一个节点,直到最后一个
            while(temp.getNext()!=null){
                temp = temp.getNext();
            }
            temp.setNext(node);  //把新节点挂在原链表的最后
        }
        size++;
    }
    //索引删除
    public  void index0f(){

    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder("[");
        //1.临时变量,指向链表中的每一个节点
        Node temp = head;

        //获取每一个节点的值value
        while(true){
            //结束条件
            if(temp==null){
                break;
            }
            sb.append(temp.getValue()); //数据的拼接
            sb.append(","); //数据的拼接
            temp = temp.getNext();  //指向新节点

        }
        //StringBuilder replace(int start, int end, String str) 使用指定的 String的字符替换此序列的子字符串中的字符。
        if(sb.length()==1){
            sb.append("]");
        }else{
            sb.replace(sb.length()-1,sb.length(),"]");
        }
        //拼接成字符串返回
        return sb.toString();
    }

    public int size(){
        return this.size;
    }
}

//节点
class Node{
    private Object value;  //数据
    private Node next;  //下一个节点对象的地址

    public Node() {
    }

    public Node(Object value, Node next) {
        this.value = value;
        this.next = next;
    }

    public Object getValue() {
        return value;
    }

    public void setValue(Object value) {
        this.value = value;
    }

    public Node getNext() {
        return next;
    }

    public void setNext(Node next) {
        this.next = next;
    }

    @Override
    public String toString() {
        return "Node{" +
                "value=" + value +
                ", next=" + next +
                '}';
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Node node = (Node) o;
        return Objects.equals(value, node.value) &&
                Objects.equals(next, node.next);
    }

}

3.2 Set 接口

  • 无序不可重复
  • 没有新增方法,继承Collection接口。
  • 无序: 存储数据的顺序与添加的顺序不同
  • 元素的存储顺序,不由存放顺序而定,容器有自己的一套存放顺序的规则。
  • 普通for循环, 用不了,因为Set集合的元素是没有下标的,不可以通过下标获取

  Set接口下有一个 HashSet 实现类,HashSet的底层是用 HashMap 实现的。查询效率高。

Set<String> set = new HashSet<>();
        set.add("AAAA");
        set.add("CCCC");
        set.add("EEEE");
        set.add("DDDD");
        set.add("BBBB");

        for (String s : set) { System.out.println(s); }
//boolean add(E e) 如果指定的元素尚不存在,则将其添加到此集合(可选操作)。
        set.add("FFFF");
//boolean addAll(Collection<? extends E> c) 如果指定集合中的所有元素尚未存在(可选操作),则将其添加到此集合中。
        Set<String> s=new HashSet<>();
        s.add("HHHH");
        s.add("IIII");
        set.addAll(s);
        System.out.println(set);
//void clear() 从该集合中删除所有元素(可选操作)。
        s.clear();
        System.out.println(s);
//boolean contains(Object o) 如果此set包含指定的元素,则返回 true 。
        System.out.println(set.contains("AAAA"));
//boolean containsAll(Collection<?> c) 如果此集合包含指定集合的所有元素,则返回 true 。
        s.add("AAAA");
        s.add("HHHH");
        System.out.println(set.contains(s));
//static <E> Set<E> copyOf(Collection<? extends E> coll) 返回包含给定Collection的元素的 unmodifiable Set 。
        System.out.println(Set.copyOf(s));
//boolean equals(Object o) 将指定对象与此set进行相等性比较。
        System.out.println(set.equals(s));
//boolean isEmpty() 如果此集合不包含任何元素,则返回 true 。
        System.out.println(set.isEmpty());
//Iterator<E> iterator() 返回此set中元素的迭代器。
        Iterator<String> it= set.iterator();
        while(it.hasNext()){
            System.out.println(it.next());
        }
//static <E> Set<E> of() 返回包含零元素的不可修改集。
        System.out.println(Set.of());
//static <E> Set<E> of(E e1) 返回包含一个元素的不可修改集。
        System.out.println(Set.of(set));
//boolean remove(Object o) 如果存在,则从该集合中移除指定的元素(可选操作)。
        set.remove("HHHH");
        System.out.println(set);

//boolean removeAll(Collection<?> c) 从此集合中删除指定集合中包含的所有元素(删除交集)。

//boolean retainAll(Collection<?> c) 仅保留此集合中包含在指定集合中的元素(保留交集)。

//int size() 返回此集合中的元素数(基数)。
        System.out.println(set.size());

//Object[] toArray() 返回包含此set中所有元素的数组。
        Object [] ss=set.toArray();
        System.out.println(Arrays.toString(ss));
//<T> T[] toArray(T[] a) 返回一个包含此set中所有元素的数组; 返回数组的运行时类型是指定数组的运行时类型。


3.2.1 TreeSet 类
  • 继承自AbstractSet类 爷爷类为Set接口
  • 底层结构: 红黑树(平衡二叉树)
  • 特点: 有序(存储数据默认升序),存放的顺序与内部存储的顺序不同->set接口的特点,去重
1、构造器
TreeSet()构造一个新的空树集,根据其元素的自然顺序进行排序。
TreeSet(Collection<? extends E> c)构造一个新的树集,其中包含指定集合中的元素,并根据其元素的 自然顺序进行排序 。
TreeSet(Comparator<? super E> comparator)构造一个新的空树集,根据指定的比较器进行排序。
TreeSet(SortedSet< E > s)构造一个包含相同元素并使用与指定有序集相同排序的新树集。
TreeSet set3 = new TreeSet<>();
TreeSet<String> ts=new TreeSet<>();
2、常用方法(一些)
变量和类型方法描述
booleanadd(E e)如果指定的元素尚不存在,则将其添加到此集合中。
booleanaddAll(Collection<? extends E> c)将指定集合中的所有元素添加到此集合中。
Eceiling(E e)返回此set中大于或等于给定元素的 null元素,如果没有这样的元素,则 null 。
voidclear()从该集中删除所有元素。
Objectclone()返回此 TreeSet实例的浅表副本。
booleancontains(Object o)如果此set包含指定的元素,则返回 true 。
Iterator< E >descendingIterator()以降序返回此集合中元素的迭代器。
NavigableSet< E >descendingSet()返回此set中包含的元素的逆序视图。
Efirst()返回此集合中当前的第一个(最低)元素。
Efloor(E e)返回此set中小于或等于给定元素的最大元素,如果没有这样的元素,则 null 。
Ehigher(E e)返回此集合中的最小元素严格大于给定元素,如果没有这样的元素,则 null 。
booleanisEmpty()如果此集合不包含任何元素,则返回 true 。
Iterator< E>iterator()以升序返回此集合中元素的迭代器。
Elast()返回此集合中当前的最后一个(最高)元素。
Elower(E e)返回此集合中的最大元素严格小于给定元素,如果没有这样的元素,则 null 。
EpollFirst()检索并删除第一个(最低)元素,如果此组为空,则返回 null 。
EpollLast()检索并删除最后一个(最高)元素,如果此集合为空,则返回 null 。
booleanremove(Object o)如果存在,则从该集合中移除指定的元素。
intsize()返回此集合中的元素数(基数)。
NavigableSet< E >subSet(E fromElement, boolean fromInclusive, E toElement, boolean toInclusive)返回此set的部分视图,其元素范围为 fromElement到 toElement 。
SortedSet< E>subSet(E fromElement, E toElement)返回此set的部分视图,其元素范围从 fromElement (含)到 toElement (独占)。
SortedSet< E >tailSet(E fromElement)返回此set的部分视图,其元素大于或等于 fromElement 。
NavigableSet< E >tailSet(E fromElement, boolean inclusive)返回此set的部分视图,其元素大于(或等于,如果 inclusive为true) fromElement 。
//问: TreeSet是否可以存储不同类型的数据??? 不能
        /*
        TreeSet set3 = new TreeSet<>();
        set3.add("哈哈");
        set3.add(false);
        set3.add(123);
        System.out.println(set3);
        */

        TreeSet<String> ts=new TreeSet<>();

        ts.add("hahah");
        ts.add("haha");
        ts.add("hah");
        TreeSet<String> ti=new TreeSet<>();
        ti.add("1");
        ti.add("23");

        ts.addAll(ti);

        System.out.println(ts);

        //ceiling(E e)  返回此set中大于或等于给定元素的 null元素,如果没有这样的元素,则  null 。
         ts.ceiling("ti");

         //**contains(Object o)**如果此set包含指定的元素,则返回 true 。
        System.out.println(ts.contains("hah"));

        //**first()**返回此集合中当前的第一个(最低)元素。
        System.out.println(ts.first());

        //**last()**返回此集合中当前的最后一个(最高)元素。
        System.out.println(ts.last());

4、比较器 Comparable接口;Comparator接口

TreeSet存储员工类型的数据: 存储员工类型的数据?
   存储自定义的引用数据类型的数据:去重。排序,都要求实现比较器

  • 比较器:
    内部比较器 | 自然排序
    实现
    Comparable接口,重写compareTo方法,在方法中自定义比较规则
  • 外部比较器 | 定制排序
    实现Comparator接口,重写compare方法,方法中定义比较规则
  • 区别:
    外部比较器灵活,便于后期维护的
    内部比较器,每次修改源代码,耦合度高,不变与后期维护

排序:

  先是否存在指定使用哪一个外部比较器比较存储的数据的大小,如果有使用外部比较器;如果没有外部比较器,继续向下判断存储的数据类型上是否存在默认的内部比较规则,如果存在使用内部比较规则比较两个数据的大小都不存在抛出异常 ClassCastException

4.1、内部比较器:Comparable接口
  • 内部比较器 | 自然排序

  • 实现Comparable接口,重写compareTo方法,在方法中自定义比较规则

public class Emp implements Comparable<Emp>{
 @Override
    public int compareTo(Emp o) {
        return Double.compare(o.getSal(),this.getSal());
    }
}
public class TreeSet03 {
    public static void main(String[] args) {
        //new TreeSet();使用默认比较规则-》内部比较器
        TreeSet<Emp> tree = new TreeSet<Emp>();
      	System.out.println(tree);
    }
}
4.2、外部比较器:Comparator接口
  • 外部比较器 | 定制排序
  • 实现Comparator接口,重写compare方法,方法中定义比较规则
//自定义比较规则实现类
public class Demo implements Comparator<Emp>{

    @Override
    public int compare(Emp o1, Emp o2) {
        return o2.getEmpno()-o1.getEmpno();
    }
}

public class TreeSet03 {
    public static void main(String[] args) {
			//TreeSet(Comparator<? super E> comparator) 构造一个新的空树集,根据指定的比较器进行排序。
			TreeSet<Emp> tree = new TreeSet<Emp>(new Demo());  //Comparator comparator = new Demo();
        tree.add(new Emp(1003,"赵丽颖",3000,10, State.BUSY));
        tree.add(new Emp(1002,"迪丽热巴",1000,10, State.BUSY));
        System.out.println(tree);
    }
}
4.3 匿名内部类与Lambda表达式改写比较器
  • 当方法|构造器参数为接口类型的时候,实参可以考虑是否可以通过一个Lambda表达式进行传递

  • lambda可以让行为作为参数|数据传递,配合函数式接口,可以让定义与实现变的更加简单灵活

public class SetDemo01 {
    public static void main(String[] args) {			
				//匿名内部类   简化实现类IMPL
        Comparator<Person> com = new Comparator<Person>(){

            @Override
            public int compare(Person o1, Person o2) {
                return o2.getAge() - o1.getAge();
            }
        };

        //Lambda
        com = (Person o1, Person o2)->{
            return o1.getAge() - o2.getAge();
        };

        //指定使用外部比较规则
        //TreeSet<Person> tree= new TreeSet<Person>(com);
        TreeSet<Person> tree= new TreeSet<Person>((Person o1, Person o2)->{
            return o1.getAge() - o2.getAge();
        });

        tree.add(new Person("胡歌",35));
        tree.add(new Person("大表哥",30));
        tree.add(new Person("金城武",34));
        tree.add(new Person("谢霆锋",30));

        System.out.println(tree);
    }
}

//外部比较器
class Impl implements Comparator<Person>{

    @Override
    public int compare(Person o1, Person o2) {
        return o1.getAge() - o2.getAge();
    }
}
4.4 练习
/*
* Arrays工具类 操作数组的工具类
    练习:
        定义一个User类型的数组,使用Arrays.sort方法对这个数据做升序排序
            排序规则: 要求按照用户编号降序排序
            排序规则: 要求按照用户员工的余额升序排序
            分别打印
        static void sort(Object[] a) 根据元素的natural ordering ,将指定的对象数组按升序排序。
        static <T> void sort(T[] a, Comparator<? super T> c) 根据指定比较器引发的顺序对指定的对象数组进行排序。*/
public class SetDemo02 {

    public static void main(String[] args) {


        User user1=new User(101,"123",10000.00);
        User user2=new User(102,"1234",10100.00);
        User user3=new User(103,"1235",12900.00);
        User user4=new User(105,"1256",12000.00);
        User user5=new User(104,"1257",15000.00);

        Comparator<User> com =new Comparator<User>() {
            @Override
            public int compare(User o1, User o2) {
                return o1.getNo() - o2.getNo();
            }
        };
        Set<User> ss=new TreeSet<>(com);
        ss.add(user1);
        ss.add(user2);
        ss.add(user3);
        System.out.println(ss);

       User[] arr = {user1 ,user2 ,user3 ,user4,user5};
       Arrays.sort(arr,((User o1, User o2)-> {return o1.getNo() - o2.getNo();}));
       System.out.println(Arrays.toString(arr));

        Arrays.sort(arr,
                ((User o1, User o2)->{return Double.compare(o1.getMoney(),o2.getMoney());})
        );
        System.out.println(Arrays.toString(arr));
    }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值