Java集合

news2025/9/19 2:11:01

一、集合概述


1、数组的特点

  • 数组的大小是固定的,一旦创建后,数组的大小是无法改变的。
  • 数组只能存储相同类型的数据。
  • 数组查询效率高(有索引,元素内存连续分配),增删效率低(不断的扩容)。

2、数组和集合的区别

相同点:

  • 都是容器,都可以存储多个数据。
  • 都可以存储引用类型的数据。

区别:

  • 数组长度不可变。
  • 集合长度可变。
  • 数组既可以存储基本类型数据,也可以存储引用类型数据。
  • 集合只能存储引用类型数据,如果要存储基本类型,需要存储对应的包装类。

3、为什么要用集合?

数组的缺点: 不灵活,容量需要事先定义好,不能随着需求的变化而扩容。

但是我们的开发又不可能离开数组,所以最初就只能依靠一些数据结构来实现动态的数组处理,其中最为重要的两个数据结构:链表、数组,但是面对这些数据结构的实现又不得不面对如下的问题?

  • 数据结构的代码实现困难,对于一般的开发者是无 法进行使用的。

  • 对于链表或二叉树当进行更新处理的时候维护是非常麻烦的。

  • 对于链表或二叉树还需要尽可能保证其操作的性能。


正是因为这样的原因,所以从JDK1.2开始Java引入了集合的概念,主要就是对常见的数据结构进行完整的实现包装,并且提供了一些列接口和实现类来帮助用户减少数据结构所带来的开发困难。

最初的集合实现由于Java本身的技术所限,所以对数据的控制并不严格,全部采用了Object类型进行数据的接收;在JDK1.5之后由于泛型技术的推广,集合框架也得到了良好的改进,可以直接利用泛型来保存相同类型的数据;随着数据量的不断增加,从JDK1.8开始集合框架中的实现算法也得到了良好的性能提升。

image-20221109173759470

二、Collection集合


java.util.Collection<E> 是单列集合操作的最大的父接口,在该接口中定义了单列集合的所有操作。

在这里插入图片描述

Collection接口实现类的特点:

  • 有些Collection的子接口/实现类,可以存放重复的元素,有些不可以。
  • 有些Collection的子接口/实现类,有些是有序的(如 List),有些不是有序的(如 Set)。
  • Collection接口没有直接的实现子类,是用过它的子接口Set和List来实现的。

1、Collection集合常用方法

方法名称功能
boolean add(E e)添加单个元素
boolean addAll(Collection coll)把coll集合中的所有元素复制一份,并添加到当前集合中
void clear()清空集合中的所有元素
boolean contains(Object o)判断当前集合中是否包含指定的数据 (需要equals方法支持)
boolean isEmpty()判断当前合是否为空
boolean remove(Object o)删除(有相同元素,只能删除一个)(需要equals方法支持)
int size()获取集合中元素的个数
Object[] toArray()将集合变成Object数组返回
Iterator<E> iterator()返回此集合中元素的迭代器

在进行集合操作的时候有两个方法最为常用:【添加数据】add()、【输出数据】iterator(),在JDK1.5版本之前Collection只是一个独立的接口,但是从JDK1.5之后提供了Iterable父接口,并且在JDK1.8之后 Iterable 接口也得到一些扩充。

但是往往我们玩的都是Collection的两个子接口: List(有序有索引可重复)、Set(无序不可以重复)接口。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-adjokWQR-1668175055586)(Java%E9%9B%86%E5%90%88.assets/image-20221109175927326.png)]


使用场景的总结:

1、如果希望元素可以重复,又有索引,索引查询要快?

  • 用 ArrayList集合,基于数组的。(用的最多,例如获取用户数据等等)

2、如果希望元素可以重复,又有索引,增删首尾操作快?

  • 用 LinkedList集合,基于链表的。(栈、队列、排队系统)

3、如果希望增删改查都快,但是元素不重复、无序、无索引。

  • 用 HashSet集合,基于哈希表的。

4、如果希望增删改查都快,但是元素不重复、有序、无索引。

  • 用 LinkedHashSet集合,基于哈希表和双链表。

5、如果要对对象进行排序。

  • 用 TreeSet集合,基于红黑树。后续也可以用List集合实现排序(sort方法)。

2、Collection集合的遍历元素

(1) 使用Iterator(迭代器)遍历

我们知道Collection继承了Iterable接口,而在Iterable接口中定义了一个iterator()抽象方法,用于返回一个Iterator对象即迭代器对象,来遍历集合中所有元素。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cdHvnqm8-1668175624271)(Java%E9%9B%86%E5%90%88.assets/image-20221109205507959.png)]

而在Collection接口中重写了Iterable接口的iterator()方法,所以Collection的 子接口/实现类 都会有这个iterator()方法。

在这里插入图片描述
在这里插入图片描述

  • Iterator对象称为迭代器,主要用于遍历 Collection 集合中的元素。(因为它不能使用for+get(索引)方式取元素)
  • 所有实现了Collection接口的集合类都有一个iterator()方法,用于返回一个Iterator接口的实现类对象,即迭代器对象。
  • Iterator仅用于遍历集合,Iterator本身并不存放对象。


Iterator接口中的方法:

方法功能
boolean hasNext()如果仍有元素可以迭代,则返回 true
E next()返回迭代的下一个元素。
default void remove()使用迭代器删除集合中的元素,它会自动更新迭代器,并且更新集合。

迭代器的执行原理:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2sUCo2Cp-1668176087761)(Java%E9%9B%86%E5%90%88.assets/image-20221109222556515.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8V2Pz6SF-1668176087762)(Java%E9%9B%86%E5%90%88.assets/image-20221109222446475.png)]

迭代器源代码分析:

在这里插入图片描述

注意:

  • 在调用next()方法之前必须先调用hasNext()方法来检测下一个元素是否存在。若不调用且下一条记录无效时(也就是已经遍历完所有元素),再调用next()会抛出NoSuchElementException异常。

  • 当while循环结束后,iterator迭代器会指向最后一个元素,如果希望再次遍历集合,需要重新获取新的迭代器对象。

  • 如果在迭代器中添加删除指定元素,则会报ConcurrentModificationException并发修改异常。

    • 参考:https://blog.csdn.net/yztfst/article/details/97834440
  • 如果要在迭代器中删除指定元素,需要调用iterator的remove()方法,他会自动更新迭代器,并且更新集合。


(2) 使用增强for循环遍历

增强for循环,JDK1.5新特性

增强for循环可以代替iterator迭代器,它只能用于遍历数组或集合。

语法格式:

for(元素类型 变量名 :集合或数组名){
    sout(变量名)
}

如果遍历数组:foreach底层源码是普通for循环。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pHPiOcge-1668180400683)(Java%E9%9B%86%E5%90%88.assets/image-20221109230502773.png)]


如果遍历集合:foreach底层源码是iterator迭代器(简化版的迭代器),只能对集合进行遍历操作。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uXXgjYUU-1668180400683)(Java%E9%9B%86%E5%90%88.assets/image-20221109230702124.png)]

扩展:使用指定编码编译 javac -encoding utf-8 xx.java


三、常见的数据结构

数据接口有:数组、队列、栈、链表、树、散列、堆、图。

1、栈

特点:先进后出、后进先出、入栈(压栈)、出栈(弹栈)。


2、队列

特点: 先进先出、后进后出(例如排队做核酸)

在这里插入图片描述


3、数组

特点:查询快(有索引、元素内存连续分配)、增删慢(不断扩容)。

在这里插入图片描述


4、链表

特点:查询慢(需要遍历),增删快(不需要创建新的链表,只需修改链表中节点保存的地址)。

单项链表:
在这里插入图片描述


双向链表:
在这里插入图片描述

链表查询慢的原因:

  • 它需要遍历链表中的节点,然后使用算法判断是从前向后查,还是从后向前查。
  • 从前向后查:要查询节点的编号<节点数/2 。
  • 从后向前查:要查询节点的编号>=节点数/2。

5、树

在这里插入图片描述

  • 结点:树中的数据元素都称为结点。例如 A、B、C、D、E等等
  • 根:最上面的结点称之为根,一颗树只有一个根且由根发展而来,从另外一个角度来说,每个结点都可以认为是其子树的根。
  • 父亲:结点的上层结点,如图中,结点K的父亲是E、结点L的父亲是G。
  • 结点的度:结点所拥有的子树的个数称之为结点的度,如结点B的度为3
  • 树叶:度为0的结点,也叫作终端结点,图中D、K、F、L、H、I、J都是树叶。
  • 分支结点:度不为0的结点,也叫作非终端结点或内部结点,图中根、A、B、C、E、G都是分支结点
  • 结点的层次:从根节点到树中某结点所经路径上的分支树称为该结点的层次,根节点的层次规定为1,其余结点的层次等于其父亲结点的层次+1。

二叉树

二叉树是每个结点最多有两个子树的树结构。通常子树被称作“左子树”(left subtree)和“右子树”(right subtree)。(左边小、右边大)

在这里插入图片描述


查找二叉树

二叉树的一个重要应用是在它们查找中的使用,假设树中的每个结点存储一项数据,使得二叉树成为二叉查找树的性质是:对于树中的每个结点X,它的左子树中所有项的值小于X,而它的右子树中所有项的值大于X,这意味着该树所有的元素可以用某种一致的方式排序。

在这里插入图片描述


平衡二叉树

在生成二叉树/二叉查找树的时候是非常容易失衡的,造成的最坏的情况就是一边倒(只有左子树/右子树),这样将会导致树的检索效率大大降低,所以为了维持二叉树的平衡,大牛们提出了各种实现的算法,比如:AVL树–每个结点的左子树和右子树深度最多差1。

在这里插入图片描述


红黑树

红黑树顾名思义就是结点是红色或者黑色的平衡二叉树,它通过颜色的约束来维持着二叉树的平衡。

对于一颗有效的红黑树而言我们必须增加如下规则:

  • 每个结点都只能是红色或者黑色;
  • 根节点是黑色;
  • 每片叶子都是黑色的;
  • 如果一个结点是红色的,则它的两个子节点都是黑色的,也就是说在一条路径上不能出现相邻的两个红色结点;
  • 从任意一个结点到其每个叶子的所有路径都包含着相同数目的黑色结点。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BMJz2C51-1668183144235)(4_红黑树.png)]

这些约束强制了红黑树的关键性质:从根到叶子的最长的可能路径不多于最短的可能路径的两倍长。结果就是这棵树大致上是平衡的,因为插入、删除和查找某个值得最坏情况时间都要求与树的高度成比例,这个高度理论上限允许红黑树只在最坏情况下都是高效的。


四、泛型


1、泛型概述

集合它可以存放任意对象,当把对象存储到集合后,他们都会被提升成Object类型。然后我们再取出每一个对象并且进行相应操作时,必须采用强制类型转换。

public class Demo01Generic {
    public static void main(String[] args) {
        // 创建一个ArrayList集合对象,指定存储数据的类型为String
        ArrayList<String> list = new ArrayList<>();
        list.add("aa");
        list.add("bbb");
        list.add("cccc");

        // 将运行时异常,提前到了编译时期,降低了程序员的工作量
        //list.add(1000); //只能存String类型数据

        // 使用增强for进行遍历
        for (String str : list) {
            System.out.println(str + "的长度: " + str.length());
        }

        System.out.println("===================");
        
        // 创建集合,不指定存储数据的类型
        // 默认按照Object类型处理
        ArrayList list2 = new ArrayList();
        list2.add("aa");
        list2.add("bbb");
        list2.add("cccc");

        // 可以存
        // 但是取出来进行强制类型转换,报出类型转换异常
        list2.add(2022);

        // 使用增强for进行遍历
        for (Object obj : list2) {
            // 因为创建ArrayList集合对象时,并没有指定存储数据的类型(泛型),
            // 所以内部存储的所有内容均被当做Object类型处理
            // 必须做强制类型转换(向下转型),存在安全隐患:类型转换异常 ClassCastException
            String str = (String) obj;
            System.out.println(obj + "的长度: " + str.length());
        }
    }
}

在这里插入图片描述

为什么会报错ClassCastException?因为上述的ArrayList集合只能存储同一类型对象(例如list2存储的都是字符串对象),当取出String类型数据时需要强转,即Object强转成String,又因为元素2022它强转后是Integer而不是String类型,所以把Integer类型的数据赋值给String类型后就会报ClassCastException类型转换异常。解决方案:使用泛型来约束集合存储指定类型数据。


什么是泛型?

泛型是程序设计语言的一种风格或范式。

泛型允许程序员在强类型程序设计语言中编写代码时使用一些以后才指定的类型(相当于占位符,可以被预先使用),在实例化时作为参数指明这些类型(实现代码的模板化,把数据类型当做参数传递)。其目的是加强类型安全以及减少类型转换的次数。

泛型是 JDK1.5之后增加的,允许在定义类和接口以及方法时使用类型参数(Type Parameter)。泛型它可以帮助我们建立类型安全的集合。提高了代码复用性和安全性。

使用泛型的好处?

  • 可以避免强制类型转换的麻烦。
  • 将运行时异常,提前到了编译时期,降低了程序员的工作量。
  • 一旦指定泛型,数据类型将被统一。
  • 实现代码的模板化,把数据类型当做参数传递。

2、泛型的分类

泛型类、泛型接口、泛型方法。

(1) 泛型类

如何定义泛型类:在类的声明处添加泛型变量即可。

泛型变量一般用大写字母表示 , 如 T(Type),E(Element),K(Key),V(Value)

如果一次要声明多个泛型变量,中间用逗号,分割即可。例如<T,E,K,V>

格式如下:

public class 类名<泛型变量>{
}
//例如
public class MyClass<T> {
}

示例:泛型类的使用

// 定义一个泛型类
public class MyClass<T> {

    // 定义成员变量
    private T t;

    // 无参构造器
    public MyClass() {
    }

    // 有参构造器
    public MyClass(T t) {
        this.t = t;
    }

   // set/get方法
    public T getT() {
        return t;
    }

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

    // toString方法
    @Override
    public String toString() {
        return "MyClass{" +
                "t=" + t +
                '}';
    }
}

测试类:

public class Demo02Generic {
    public static void main(String[] args) {
        // 使用无参构造器创建对象,并指定泛型
        MyClass<String> mc = new MyClass<>();
        // 使用set方法为成员变量赋值
        mc.setT("helloworld");
        System.out.println(mc); //MyClass{t=helloworld}

        // 使用get方法取值
        String str = mc.getT(); //因为创建对象的时候传了泛型,所以返回值类型就是Stirng类型
        System.out.println(str); //helloworld

        // 使用有参构造器创建对象
          MyClass<Integer> mc02 = new MyClass<>(100);//发生自动装箱操作
        //错误示范: 左侧<>中指定了Integer类型,有参构造右侧只能传递Integer数据,不能传递字符串
        //MyClass03<Integer> mc02 = new MyClass03<>("100");
      

        //调用toString方法获取数据
        String s2 = mc02.toString();
        System.out.println(s2); //MyClass{t=100}
    }
}

在这里插入图片描述


(2) 泛型方法

泛型方法可以是普通方法、静态方法和构造器方法。

泛型方法定义格式:

修饰符 <泛型变量> 返回值类型 方法名(参数类型 参数列表){
}
//例如Collections的两个泛型方法
public <T> T[] toArray(T[] a){
  return s.toArray(a); 
}

public static <T> boolean addAll(Collection<? super T> c, T... elements) {
    boolean result = false;
    for (T element : elements)
        result |= c.add(element);
    return result;
}

示例:泛型方法的使用

public class MyClass<T> {

    /*
       这种定义方法不叫泛型方法(因为它使用类上定义的泛型)
    */
    public void method(T t){
        System.out.println(t);
    }

    //定义非静态泛型方法
    //泛型方法: 该泛型只属于当前方法使用
    public <E> void show(E e) {
        System.out.println(e);
    }


     /*
        错误示范:
            静态方法必须使用类名直接调用,和对象无关
            但是类上的泛型,必须创建对象后才能确定具体的类型
            然而静态方法和对象无关,调用时根本没有对象,就没有泛型
        总结:
            静态方法,不能使用类上定义的泛型,只能使用方法中的泛型
     */
    /*public static void fun(T t){
        System.out.println(t);
    }*/


    //定义静态泛型方法
    public static <K> void test(K k) {
        System.out.println(k);
    }
}

在这里插入图片描述
测试类:

public class Demo01GenericMethod {
    public static void main(String[] args) {
        MyClass<String> mc01 = new MyClass<>();
        mc01.method("hello");

        /*
            错误示范:
                method方法使用类上的泛型已经被确定为了String,
                就不能传递String以外的类型
         */
        //mc01.method(100);
        
        /*
            正确写法:
                show方法上有自己的泛型,
                根据调用方法传递的参数的类型,来确定方法上泛型的类型
         */
        mc01.show("World");
        mc01.show(100);
        mc01.show(new Student("zs", 18));

        /*
            正确写法:
                test方法上有自己的泛型,
                根据调用方法传递的参数的类型,来确定方法上泛型的类型
         */
        MyClass.test("Java");
        MyClass.test(200);
        MyClass.test(new Student("ls",38));
    }
}

在这里插入图片描述


(3) 泛型接口

泛型接口定义格式如下:

public interface 接口名称<泛型变量> {
}
//例如
public interface Iterable<T> {}
public interface Collection<E> extends Iterable<E> {}
public interface List<E> extends Collection<E> {}
public interface Set<E> extends Collection<E> {}
public interface Map<K,V> {}

示例:泛型接口

public interface MyInter<T> {
    // 抽象方法
    /*public abstract */void method(T t);
}

实现类:MyInterImplA

/*
	已经确定接口要传的类型 String
 */
public class MyInterImplA implements MyInter<String> {
    @Override
    public void method(String str) {
        System.out.println(str);
    }
}

实现类:MyInterImplB

/*
    不确定接口要传的类型
    把实现类定义成泛型类,在实现接口时,就可以使用类上定义的泛型啦QAQ
 */
public class MyInterImplB<T> implements MyInter<T> {
    @Override
    public void method(T t) {
        System.out.println(t);
    }
}

测试类:

public class MyTest {
    public static void main(String[] args) {
        MyInterImplA mia = new MyInterImplA();
        mia.method("Hello");

        MyInterImplB<String> mib = new MyInterImplB<>(); //指定泛型
        mib.method("World");

        MyInterImplB<Student> mib2 = new MyInterImplB<>();//指定泛型
        mib2.method(new Student("zs",18));
    }
}

在这里插入图片描述


3、泛型通配符

泛型通配符: ? 可以理解成占位符,用来匹配泛型的,但是不能使用?定义泛型。

主要应用场景: 定义参数/变量时,不能确定变量的具体类型时,使用?代替。

示例1:

public class Demo01TongPeiFu {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("AAA");
        list.add("BBB");
        list.add("CCC");
        Set<Integer> set = new HashSet<>();
        set.add(111);
        set.add(222);
        set.add(333);
        //调用方法
        print(list);
        print(set);
        System.out.println("-------------");

        //调用方法
        print2(list);
        print2(set);

    }

    /**
     * 定义一个方法,完成以上两个集合的遍历
     * 泛型通配符: ? 就是一个占位符, 用来匹配泛型的,但是不能使用?定义泛型。
     * @param coll
     */
    public static void print2(Collection<?> coll) {
        for (Object o : coll) {
            System.out.println(o);
        }
    }

    /*
           定义一个方法,完成以上两个集合的遍历
               目前: 把print方法定义成了泛型方法
           方法参数:
               使用Collection接口定义变量,Collection接口在定义时是有泛型的,
               使用Collection接口定义变量,需要指定泛型
               泛型是不存在的多态的
           此处:
               print2方法是一个泛型方法
    */
    public static <T> void print(Collection<T> coll) {
        for (T t : coll) {
            System.out.println(t);
        }
    }
}

在这里插入图片描述


示例2:

public class Demo02TongPeiFuNotice {
    public static void main(String[] args) {
        List<Object> list1 = new ArrayList<>();//右侧<>中省略不写,就是Object
        List<Object> list2 = new ArrayList<Object>();//右侧<>中写Object也是可以的
        //List<Object> list3 = new ArrayList<String>();//错误: 左右两边<>中的数据类型必须一致,泛型不存在多态
        //List<Object> list4 = new ArrayList<Integer>();//错误: 左右两边<>中的数据类型必须一致,泛型不存在多态
        //List<Object> list5 = new ArrayList<Student>();//错误: 左右两边<>中的数据类型必须一致,泛型不存在多态
        List list6 = new ArrayList(); //不加泛型默认是Object类型

        //?通配符: 用来匹配泛型的,不能用来定义泛型
        //主要的应用场景: 定义参数/变量时,不能确定变量的具体类型时,使用?代替
        //?: 代表任意一种引用类型
        List<?> list;
        list = new ArrayList<>();//<>不写数据类型代表Object
        list = new ArrayList<String>(); //String
        list = new ArrayList<Integer>(); //Integer
        list = new ArrayList<Student>(); //Student
/*
	注意事项:
       1.泛型是不存在多态的,左侧<>中写的类型必须和右侧<>中的类型保持一致(可以省略右侧<>中的内容)
       2.使用泛型通配符,定义变量:
           List<?> list 可以接收哪些对象?
                   只要是List接口实现类的任意泛型对象就可以(创建对象时,只要在<>中写上一种引用类型就行)
       3.List<?> list: 理解为它是各种泛型List集合对象的父类
*/
    }
}

在这里插入图片描述


4、泛型上限和下限

泛型通配符的限制

(1) 泛型的上限

一个父类的子类可以有任意多个,那如何表示出一个父类的任意子类呢?(找儿子)

泛型的上限:
// ?: 代表的是任意一种引用类型
        ? extends Person: 表示Person类型或者Person类型的任意子类型
        ? extends E: 表示E类型或者E类型的任意子类型

示例:泛型上限的使用

在这里插入图片描述

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

    //生成空参,满参构造,set和get方法
    public Person() {
    }

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

    @Override
    public String toString() {
        return "Person{" + "name='" + name + '\'' + ", 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;
    }
}
//Worker类 工人
public class Worker extends Person {
    //根据父类生成空参,满参构造
    public Worker() {
    }

    public Worker(String name, int age) {
        super(name, age);
    }

    @Override
    public String toString() {
        return "Worker{" + "name='" + getName() + '\'' + ", age=" + getAge() + '}';
    }
}
//Teacher类
public class Teacher extends Worker {
    //根据父类生成空参,满参构造
    public Teacher() {
    }

    public Teacher(String name, int age) {
        super(name, age);
    }

    @Override
    public String toString() {
        return "Teacher{" + "name='" + getName() + '\'' + ", age=" + getAge() + '}';
    }
}
//JavaTeacher类
public class JavaTeacher extends Teacher {
    public JavaTeacher() {
    }
    //根据父类生成空参,满参构造

    public JavaTeacher(String name, int age) {
        super(name, age);
    }

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

测试类:

@SuppressWarnings("all") //抑制警告
public class Demo01GenericShangXian {
    public static void main(String[] args) {
        ArrayList<Person> list1 = new ArrayList<>();
        list1.add(new Person("zs", 18));
        list1.add(new Person("ls", 28));
        list1.add(new Person("ww", 38));

        ArrayList<Worker> list2 = new ArrayList<>();
        list2.add(new Worker("zs01", 18));
        list2.add(new Worker("ls01", 28));
        list2.add(new Worker("ww01", 38));

        ArrayList<Teacher> list3 = new ArrayList<>();
        list3.add(new Teacher("zs02", 18));
        list3.add(new Teacher("ls02", 28));
        list3.add(new Teacher("ww02", 38));

        ArrayList<String> list4 = new ArrayList<>();
        list4.add("aaa");
        list4.add("bbb");

        ArrayList<Integer> list5 = new ArrayList<>();
        list5.add(100);
        list5.add(200);


        print(list1);
        print(list2);
        print(list3);
        // print(list4); //错误:String不是Person的子类
        // print(list5); //错误:Integer不是Person的子类
    }

    /**
     *  定义一个方法,只能完成以下3个集合的遍历 
     *       ArrayList<Person>、ArrayList<Worker>、ArrayList<Teacher>
     *       Worker是Person的子类,Teacher也是Person的子类
     *       ? extends Person:  代表Person类型或者Person类型的任意子类类型
     * @param list
     */
    public static void print(ArrayList<? extends Person> list) {
        for (Person person : list) {
            System.out.println(person);
        }
		 System.out.println("---------------");
    }
}

在这里插入图片描述

(2) 泛型的下限

一个子类的父类可以有任意多个,如何表示一个子类的任意父类类型呢?(找爹)

泛型的上限:
// ?: 代表的是任意一种引用类型
        ? super JavaTeacher: 代表JavaTeacher类型或者JavaTeacher类型的任意父类类型
        ? super T:           代表T类型或者T类型的任意父类类型

示例:泛型下限的使用

在这里插入图片描述

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

    //生成空参,满参构造,set和get方法
    public Person() {
    }

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

    @Override
    public String toString() {
        return "Person{" + "name='" + name + '\'' + ", 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;
    }
}
//Worker类 工人
public class Worker extends Person {
    //根据父类生成空参,满参构造
    public Worker() {
    }

    public Worker(String name, int age) {
        super(name, age);
    }

    @Override
    public String toString() {
        return "Worker{" + "name='" + getName() + '\'' + ", age=" + getAge() + '}';
    }
}
//Teacher类
public class Teacher extends Worker {
    //根据父类生成空参,满参构造
    public Teacher() {
    }

    public Teacher(String name, int age) {
        super(name, age);
    }

    @Override
    public String toString() {
        return "Teacher{" + "name='" + getName() + '\'' + ", age=" + getAge() + '}';
    }
}
//JavaTeacher类
public class JavaTeacher extends Teacher {
    public JavaTeacher() {
    }
    //根据父类生成空参,满参构造

    public JavaTeacher(String name, int age) {
        super(name, age);
    }

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

测试类:

public class Demo02GenericXiaXian {
    public static void main(String[] args) {
        ArrayList<Person> list1 = new ArrayList<>();
        list1.add(new Person("zs", 18));
        list1.add(new Person("ls", 28));
        list1.add(new Person("ww", 38));

        ArrayList<Worker> list2 = new ArrayList<>();
        list2.add(new Worker("zs01", 18));
        list2.add(new Worker("ls01", 28));
        list2.add(new Worker("ww01", 38));

        ArrayList<Teacher> list3 = new ArrayList<>();
        list3.add(new Teacher("zs02", 18));
        list3.add(new Teacher("ls02", 28));
        list3.add(new Teacher("ww02", 38));

        ArrayList<String> list4 = new ArrayList<>();
        list4.add("aaa");
        list4.add("bbb");

        ArrayList<Integer> list5 = new ArrayList<>();
        list5.add(100);
        list5.add(200);

        ArrayList<JavaTeacher> list6 = new ArrayList<>();
        list3.add(new JavaTeacher("zs02", 18));
        list3.add(new JavaTeacher("ls02", 28));
        list3.add(new JavaTeacher("ww02", 38));


        print(list1);
        print(list2);
        print(list3);

        // print(list4); //错误:String不是Teacher的父类
        // print(list5); //错误:Integer不是Teacher的父类
        // print(list6); //错误:JavaTeacher不是Teacher的父类
    }

    /**
     * 使用泛型下限变量一下三个集合定义一个方法
     *       ArrayList<Person> list1、ArrayList<Worker> list2 、ArrayList<Teacher> list3
     *
     * @param list
     */
    public static void print(ArrayList<? super Teacher> list) {
        for (Object o : list) {
            System.out.println(o);
        }
           System.out.println("---------------");
    }
}

在这里插入图片描述


五、List集合


ArrayList

LinkedList


六、Set集合


HashSet

LinkedHashSet

TreepSet


七、Map集合


java.util.Map<K,V>集合是双列集合的根接口,内部定义的方法,子接口/实现类都有。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CKI9L0Tm-1668175055586)(Java%E9%9B%86%E5%90%88.assets/image-20221109180206700.png)]

HashMap

LinkedHashMap

Properties

TreeMap

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/5365.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Designing ML Systems】第 6 章 :模型开发和离线评估

&#x1f50e;大家好&#xff0c;我是Sonhhxg_柒&#xff0c;希望你看完之后&#xff0c;能对你有所帮助&#xff0c;不足请指正&#xff01;共同学习交流&#x1f50e; &#x1f4dd;个人主页&#xff0d;Sonhhxg_柒的博客_CSDN博客 &#x1f4c3; &#x1f381;欢迎各位→点赞…

目标检测论文解读复现之三:基于改进YOLOv7的X光图像旋转目标检测

目标检测论文解读复现 文章目录目标检测论文解读复现前言一、摘要二、网络模型及核心创新点三、应用数据集四、实验效果五、实验结论六、投稿期刊介绍前言 此前出了目标改进算法专栏&#xff0c;但是对于应用于什么场景&#xff0c;需要什么改进方法对应与自己的应用场景有效果…

json字符串、JSNObject、JSONArray、jsonbean、list等相关的转换、过滤工具方法测试

一、准备工作 引入pom <dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.78</version> </dependency><dependency><groupId>org.projectlombok</groupId><art…

云计算 - 4 - Spark的安装与应用

云计算 - 4 - Spark的安装与应用目标Spark 的安装&#xff1a;1、下载配置 Scala1.1 下载 Scala1.2 配置 Scala 的路径1.3 测试 Scala 是否安装完成2、下载配置Spark2.1 下载Spark2.2 配置 Spark 的路径2.3 修改 Spark 的配置文件3、将文件复制到子节点4、启动Spark5、测试Spar…

nginx模块

目录 搭建域名虚拟主机 nginx索引 状态索引 访问控制 基于ip限制 基于用户限制 配置nginx官方yum源 http://nginx.org/en/linux_packages.html#RHEL-CentOS vim /etc/yum.repos.d/nginx.repo [nginx-stable] namenginx stable repo baseurlhttp://nginx.org/packages/cent…

Linux调试工具:gdb的使用

文章目录一、gdb简介二、gdb基础命令操作1.进入gdb &#xff1a;gdb 文件名2.显示代码&#xff1a;l3.开始调试&#xff1a;r4.打断点&#xff1a;b 行号5.显示断点信息&#xff1a;info b6.删断点&#xff1a;d 编号7.逐过程&#xff1a;n8.逐语句&#xff1a;s9.进入堆栈&…

JavaScript基础

目录 数据类型 基本数据类型 引用数据类型 变量 运算符 算数运算符 赋值运算符 字符串连接符 关系运算符 逻辑运算符 三目运算符 分支语句 循环语句 流程控制语句 错误处理 函数 数组 对象 内置对象 String RegExp Math Date 全局函数 简介&#xff1a; 是…

Nginx虚拟主机与域名解析

文章目录一、域名、dns、ip地址之间的关系二、浏览器、nginx与http协议三、虚拟主机原理四、域名解析与泛解析1.公网ip解析2.内网ip解析五、域名解析相关企业项目实战技术架构1.多用户二级域名2.短网址3.httpDNS一、域名、dns、ip地址之间的关系 域名代表了一个公司、一个人或…

C语言之文件的使用(下)

目录 前言 一、文件的随机读写 1.如何进行随机读写 2.相关函数&#xff08;含例子&#xff09; 1.fseek函数 2.ftell函数 3.rewind函数 二、文件读取结束的判定 1.判定结束的相关函数 1.feof函数 2.ferror函数 2.不同类型文件 1.文本文件和二进制文件 2.不同文件的所判断的返回…

win10怎么安装iis

在win10系统桌面&#xff0c;点击开始菜单里的设置图标。 win10怎么安装iis 在Windows设置界面&#xff0c; 点击应用。 win10怎么安装iis 在应用界面&#xff0c;点击【程序和功能】。 win10怎么安装iis 在程序管理界面&#xff0c;点击启用或关闭Windows功能。 win10怎…

Python采集剧本杀店家数据信息,做可视化演示

前言 哈喽啊&#xff0c;友友们 有喜欢玩桌游或者剧本杀的吗 其实我自己对这个不太感兴趣哈哈&#xff0c;但是也玩过 正好又有朋友约着出去&#xff0c;就是不知道哪家店更值得去 所以趁着还有几天就用python来采集一些 店家的数据信息 并做个可视化演示吧 环境使用: P…

如何利用Dpabi,AFNI,FSL软件计算种子点的功能连接?

种子点功能连接方法基本概念和实现 种子点的功能连接基本概念功能连接在数据处理里的具体应用如何使用 Dpabi, AFNI 和 FSL 计算种子点功能连接呢?选择种子点利用DPABI软件进行种子点的功能连接利用AFNI (3dNetCorr)进行种子点的功能连接利用FSL (fslmeants + fsl_glm)进行…

Linux常用命令详解

系列文章目录 Linux 环境搭建以及xshell远程连接_crazy_xieyi的博客-CSDN博客 ls 该命令列出该目录下的所有子目录与文件。对于文件&#xff0c;将列出文件名以及其他信息。 常用选项&#xff1a; -a 列出目录下的所有文件&#xff0c;包括以. 开头的隐含文件。-d 将目录…

探花交友_第1章_项目介绍以及实现登录功能_第2节_项目介绍

探花交友_第1章_项目介绍以及实现登录功能_第2节_项目介绍 文章目录探花交友_第1章_项目介绍以及实现登录功能_第2节_项目介绍2、项目介绍2.1、项目背景2.2、市场分析2.3、目标用户群体2.4、技术方案2.5、技术架构2.6、技术解决方案2.7、技术亮点2.8、开发方式2.9、基础环境功能…

[附源码]计算机毕业设计JAVA博客系统设计

[附源码]计算机毕业设计JAVA博客系统设计 项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis M…

自适应,响应式以及图片的性能优化(响应式图片)

自适应:最常见的就是淘宝无限适配[移动端]rem单位 index.js 2.0 mirrors / amfe / lib-flexible GitCode 可以将这个淘宝无限适配的index.js引入自己的文件中 (它的核心原理就是改变html的font-size的字体大小) 响应式:一个url可以响应多端 响应式最常见的就是媒体查询 …

这款键盘你真的要考虑一下!——Keychron K3测评

家人们&#xff01;这款键盘你真的要考虑一下&#xff01;&#xff01;&#xff01; 如果你是一名程序员&#xff0c;每天在键盘上一顿噼里啪啦&#xff1b;如果你是职场人士&#xff0c;需要长期码字&#xff1b;如果你是游戏爱好者&#xff0c;对键盘有着极致追求&#xff0…

用python实现提高自己博客访问量

文章目录前言1、整体逻辑2、代码实现前言 你还在为自己博客的访问量不高而烦恼吗&#xff1f;我教你如何提高访问量 我发现CSDN上&#xff0c;自己点击自己的博客&#xff0c;可以增加访问量&#xff0c;但是在一定时间内点击同一篇博客&#xff0c;访问量无法再次增加&#x…

Vue3 - <script setup> 单文件组件语法糖的使用教程示例 (SFC)

概念 它是在 单文件组件 (SFC) 中使用组合式 API 的编译时语法糖&#xff0c;解决 vue3 中 setup() 需要繁琐将声明的变量、函数以及 import 引入的内容通过 return 向外暴露&#xff0c;才能在<template> 使用的问题。 小示例 是不是感觉似懂非懂&#xff1f;先来看个…

【蓝桥杯Web】第十四届蓝桥杯(Web 应用开发)模拟赛 1 期-大学组 | 精品题解

&#x1f4d1; 目录&#x1f53d; 前言1️⃣ 数据类型检测2️⃣ 渐变色背景生成器3️⃣ 水果叠叠乐4️⃣ element-ui 组件二次封装5️⃣ http 模块应用6️⃣ 新课上线啦7️⃣ 成语学习8️⃣ 学海无涯9️⃣ 逃离二向箔&#x1f51f; 梅楼封的一天&#x1f53c; 结语&#x1f53d…