【集合进阶单列集合Collection,List,ArrayList,LinkedList-学习笔记】

在这里插入图片描述

集合体系结构

在这里插入图片描述
List系列集合:添加的元素都是有序,可重复,有索引
Set系列集合:添加的元素是无序,不重复,无索引

Collection单列集合

Collection是单列集合的祖宗接口,它的功能是全部单列集合都可以继承使用的 Collection是一个接口
在这里插入图片描述

package com.hh.collection;

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

public class CollectionDemo1 {
    public static void main(String[] args) {
        Collection<String> coll= new ArrayList<>();
        //添加元素
        //细节1:如果我们要往List系列集合里添加数据,那么方法永远返回true,因为List系列的是允许元素重复的
        //细节2:如果我们要往Set系列集合中添加数据,如果当要添加元素不存在,方法返回true,表示添加成功;如果当要添加元素存在,方法返回false,表示添加失败;
        //因为Set系列集合不允许重复
        coll.add("aaa");
        coll.add("bbb");
        coll.add("ccc");
        System.out.println(coll);
        
        coll.clear();
        
        //细节1:因为Collection里面定义的是共性的方法,所以此时不能通过索引进行删除,只能通过元素的对象进行删除
        //细节2:方法会有一个布尔类型的返回值,删除成功返回false,删除失败返回false;如果想要删除的元素不存在就会删除失败
        coll.remove("ccc");
        
        //细节:底层是依赖equals方法进行判断是否存在的
        //所以,如果集合中存储的是自定义对象,也想通过contains方法判断是否包含,那么在javabean类中,一定要重写equals方法
        coll.contains("aaa");
        
        //判断集合是否为空
        boolean result2 = coll.isEmpty();
        System.out.println(result2);

        //获取集合长度
        int size = coll.size();
        System.out.println(size);
    }
}

Collection的遍历方式

迭代器遍历

迭代器不依赖索引在Java中的类是Iterator,迭代器是集合专用的遍历方式
格式

Iterator<E> iterator() 返回迭代器对象,默认指向当前集合的0索引

迭代器常用方法

boolean hasNext()  判断当前位置是否有元素,有元素返回true,没有元素返回false
E next()  获取当前位置的元素,并将迭代器对象移向下一个位置
package com.hh.collection;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
public class CollectionDemo2 {
    public static void main(String[] args) {
        Collection<String> coll = new ArrayList<>();
        coll.add("aaa");
        coll.add("bbb");
        coll.add("ccc");
        coll.add("ddd");
        //获取迭代器对象,迭代器对象就好比是一个箭头,指向集合的0索引
        Iterator<String> it = coll.iterator();
        while(it.hasNext()){
            String next = it.next();
            System.out.println(next);
        }
    }
}

细节注意点
1.报错NoSuchElementExpection
2.迭代器遍历完毕,指针不会复位
3.循环中只能用一次next方法
4.迭代器遍历时,不能用集合的方法进行增加或者删除

增强for遍历

增强for的底层就是迭代器,为了简化迭代器的代码书写的,实在JDK5之后出现的,其内部原理就是一个Iterator迭代器
所有单列集合数组才能用增强for进行遍历
格式

for(String s : list){
	System.out.println(s);
}
package com.hh.collection;

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

public class CollectionDemo3 {
    public static void main(String[] args) {
        Collection<String> coll = new ArrayList<>();
        coll.add("aaa");
        coll.add("bbb");
        coll.add("ccc");
        coll.add("ddd");
        //简写:coll.for+回车
        //注意:S其实就是一个第三方变量,在循环过程中依次表示集合中的每一个数据
        for (String s : coll) {
            System.out.println(s);
        }
    }
}

细节注意点
1.修改增强for中的变量,不会改变集合中原本的数据

Lambda表达式遍历

得益于JDK8开始的新技术Lambda表达式,提供了一种更简单,更直接的遍历集合的方式.

default void forEach(Consumer<? super T>action):结合Lambda遍历集合
 coll.forEach(s->System.out.println(s));
            //s依次表示集合中的每一个数字

List集合

List集合的特点:
1.有序:存和取的元素顺序一致
2.有索引:可以通过索引操作元素
3.可重复:存储的元素可以重复

List集合独有的方法

Collection的方法List都继承了,List集合因为有索引,所以多了很多索引操作的方法
在这里插入图片描述

package com.hh.listdemo;
import java.util.ArrayList;
import java.util.List;
public class ListDemo1 {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        //添加元素
        list.add("aaa");
        list.add("bbb");
        list.add("ccc");
        System.out.println(list);
        //再次集合中的指定位置插入指定元素
        //细节:原来索引上的元素会依次后移
        list.add(2,"ddd");
        System.out.println(list);

        list.remove("ddd");
        list.remove(0);//删除0索引上对应元素,并且将被删除元素作为返回值
        System.out.println(list);

        list.set(0,"qqq");//修改之后会将被修改的元素做一个返回
        System.out.println(list);

        String s = list.get(0);
        System.out.println(s);
    }
}

List集合独有的遍历方式

1.迭代器遍历
2.列表迭代器遍历
3.增强for遍历
4.Lambda表达式遍历
5.普通for遍历

package com.hh.listdemo;

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

public class ListDemo2 {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("aaa");
        list.add("bbb");
        list.add("ccc");
        list.add("ddd");

        //迭代器方式
        Iterator<String> it = list.iterator();
        while(it.hasNext()){
            System.out.println(it.next());
        }
        //增强for遍历方式
        for(String s : list){
            System.out.println(s);
        }
        //Lambda表达式方式
        list.forEach(s-> System.out.println(s));
        //普通for循环
        for (int i = 0; i < list.size(); i++) {//集合的大小是list.size()
            System.out.println(list.get(i));
        }
        //列表迭代器
        //获取列表迭代器的对象,里面的指针默认也是指向0索引的
        //额外添加了一个方法:在便利的过程中,可以添加元素
        ListIterator<String> it2 = list.listIterator();
        while(it2.hasNext()){
            String s = it2.next();
            if(s.equals("bbb")){
                it2.add("eee");
            }
        }
    }
}

在这里插入图片描述

ArrayList集合

在这里插入图片描述

LinkedList集合

底层数据结构是双链表,查询慢,增删快,但是如果操作的是首尾元素,速度也是极快的
LinkList本身多了很多直接操作首尾元素的特有API
在这里插入图片描述

泛型深入

**泛型:**是JDK5中引入的特性,可以在编译阶段约束操作的数据类型,并进行检查
泛型的格式<数据类型>
注意泛型中只能支持引用数据类型
如果没有给集合指定类型,默认认为所有的数据类型都是Object类型,此时可以往集合添加任意的数据类型
劣势:在获取数据时,无法使用其特有行为。
此时退出了泛型,可以再添加数据的时候就把类型进行统一,而且我们在获取数据是也不需要强制类型转换。
泛型的好处
1.统一数据类型
2.在运行时期的问题提前到了编译期间,避免了强制类型转换可能出现的异常,因为在编译阶段类型就能确定下来。
泛型的扩展 Java中的泛型是伪泛型
当集合中想要添加元素时,集合验证数据类型与集合泛型是否符合,若符合加入集合。在集合内的存储中,数据类型为Object,当将数据取出集合后,又将数据类型转换为原来数据类型。
泛型的细节
1.泛型中不能写基本数据类型
2.指定泛型的具体类型后,传递数据时,可以传入该类类型或者其子类类型
3.如果不写泛型,类型默认是Object

泛型可以在很多地方进行定义

泛型类

使用场景:当一个类中,某个变量的数据类型不确定时,就可以定义带有泛型的类
格式

public class ArrayList<E>{

}

此处E可以理解为变量,但是不是用来记录数据的,而是记录数据的类型,可以写成:T,E,K,V等
在这里插入图片描述

泛型方法

方法中形参类型不确定时,可以使用类名后面定义的泛型
在这里插入图片描述
泛型方法

public <T> void show(T t){

}

此处E可以理解为变量,但是不是用来记录数据的,而是记录数据的类型,可以写成:T,E,K,V等

public static<E> void addAll(ArrayList<E> list,E...e){
        for (E e1 : e) {
            list.add(e1);
        }
    }

泛型接口

public interface List<E>{

}

使用方式
1.实现类给出具体类型
2.实现类延续泛型,创建对象时再确定

泛型的继承和通配符

泛型不具备继承性,但是数据具备继承性
定义类,方法,接口的时候,如果类型不确定,就可以定义泛型
如果类型不确定,但是能知道是哪个继承体系中的,可以使用泛型的通配符

Set集合的实现类

**HashSet:**无序,不重复,无索引
LinkedHashSet:有序,不重复,无索引
TreeSet:可排序,不重复,无索引
Set接口中的方法上基本上与Collection的API一致

Set集合的遍历

package com.hh.setdemo;

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

public class SetDemo1 {
    public static void main(String[] args) {
        Set<String> s= new HashSet<>();
        boolean r1 = s.add("张三");
        boolean r2 = s.add("lisi");
        boolean r3 = s.add("wangwu");
        System.out.println(s);
        //迭代器的方法遍历
        Iterator<String> it = s.iterator();
        while(it.hasNext()){
            System.out.println(it.next());
        }
        //Lamdba表达式方法
        s.forEach(i-> System.out.println(i));
    }
}

HashSet

HashSet底层原理
HashSet集合底层采取哈希表存储数据
哈希值
1.根据HashCode方法算出来的int类型的整数
2.该方法定义在Object类中,所有对象都可以调用,默认使用地址值进行计算
3.一般情况下,会重写HashCode方法,利用对象内部的属性值计算哈希值
对象的哈希值特点
1.如果没有重写HashCode方法,不同对象计算出的哈希值是不同的
2.如果已经重写HashCode方法,不同的对象只要属性值相同,计算出的哈希值就是一样的
3.在小部分情况下,不同的属性值或者不同的地址值计算出来的哈希值也有可能一样(哈希碰撞)
HashSet底层原理
1.创建一个默认长度为16,默认加载因子为0.75的数组,数组名为table
2.根据元素的哈希值跟数组长度计算出应存入的位置
3.判断当前位置是否为null,如果是null直接存入
4.如果位置不为null,表示有元素,则调用equals方法比较属性值
5.一样:不存 不一样:存入数组,形成链表
JDK8以前:新元素存入数组,老元素挂在新元素下面
JDK8以后:新元素直接挂在老元素下面

package com.hh.setdemo;

import java.util.HashSet;

public class HashSetDemo {
    public static void main(String[] args) {
        //需求:创建一个存储学生对象的集合,存储多个学生对象,使用程序实现在控制台遍历该集合
        //要求:学生对象的成员变量值相同,我们就认为是同一个对象
        Student stu1 = new Student("张三",23);
        Student stu2 = new Student("李四",21);
        Student stu3 = new Student("王五",25);
        Student stu4 = new Student("张三",23);

        HashSet<Student> set = new HashSet<>();//此时未重写HashCode的值,判断是找的是地址值,无法去重//需要在对象类中重写HashSet
        set.add(stu1);
        set.add(stu2);
        set.add(stu3);
        set.add(stu4);

        System.out.println(set);

    }
}

LinkedHashSet

有序,不重复,无索引
**原理:**底层数据结构是依然哈希表,只是每个元素又额外的多了一个双链表的机制记录存储顺序

TreeSet

无重复,无索引,可排序
可排序:按照元素的默认规则(有小有大)排序
TreeSet集合底层是基于红黑树的数据结构实现排序的,增删改查性能都较好
TreeSet集合默认的规则
1.对于数值类型:Integer,Double,默认按照从小到大的顺序进行排序
2.对于字符,字符串:按照字符在ASCII码表中的数字升序进行排序a->b->c->…

TreeSet的两种比较方式

方式一:默认排序/自然排序:Javabean实现Comparable接口指定比较规则
方式二:比较器排序创建TreeSet对象的时候,传递比较器Comparator制定规则
使用原则:默认使用第一种,如果第一种不能满足条件,再使用第二种
在这里插入图片描述

    public int compareTo(Student o) {
        int sum = this.getChineseScore() + this.getMathScore() + this.getEnglishScore();
        int sum2 = o.getChineseScore() + o.getMathScore() + o.getEnglishScore();
        int i = sum - sum2;
        i = i == 0 ? this.getChineseScore() - o.getChineseScore() : i;
        i = i == 0 ? this.getMathScore() - o.getMathScore() : i;
        i = i == 0 ? this.getEnglishScore() - o.getEnglishScore() : i;
        i = i == 0 ? this.getAge() - o.getAge() : i;
        i = i == 0 ? this.getName().compareTo(o.getName()) : i;
        return i;
    }

方法返回值特点:
1.**负数:**表示当前要添加的元素是小的,存左边
2.**正数:**表示当前要添加的元素是大的,存右边
3.**0:**表示当前要添加的元素已经存在,舍弃
在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值