容器【基本使用、索引操作、并集、交集、差集】(二)-全面详解(学习总结---从入门到深化)

简介: 容器【基本使用、索引操作、并集、交集、差集】(二)-全面详解(学习总结---从入门到深化)



泛型中的通配符

无界通配符

“?”表示类型通配符,用于代替具体的类型。它只能在“<>”中使用。可以解决当具体类型不确定的问题。

语法结构

public void showFlag(Generic<?> generic){  }

示例

public class Generic<T> {
  private T  flag;
  public void setFlag(T flag){
    this.flag = flag;
 }
  public T getFlag(){
    return this.flag;
  }
}
public class ShowMsg {
  public void showFlag(Generic<?> generic){
  System.out.println(generic.getFlag());
 }
}
public class Test3 {
  public static void main(String[] args) {
    ShowMsg showMsg = new ShowMsg();
    Generic<Integer> generic = new  Generic<>();
    generic.setFlag(20);
    showMsg.showFlag(generic);
    Generic<Number> generic1 = new  Generic<>();
    generic1.setFlag(50);
    showMsg.showFlag(generic1);
    Generic<String> generic2 = new Generic<>();
    generic2.setFlag("old");
    showMsg.showFlag(generic2);
 }
}

实时效果反馈

1.在泛型中,无界通配符使用什么符号来表示?

A !

B ?

C #

D *

答案

1=>B

统配符的上下限定
统配符的上限限定

对通配符的上限的限定:<? extends 类型>  ?实际类型可以是上限限定中所约定的类型,也可以是约定类型的子类型;

语法结构

public void showFlag(Generic<? extends Number> generic){ }

示例

public class ShowMsg {
  public void showFlag(Generic<? extends Number> generic){
        System.out.println(generic.getFlag());
  }
}
public class Test4 {
  public static void main(String[] args) {
    ShowMsg showMsg = new ShowMsg();
    Generic<Integer> generic = new  Generic<>();
    generic.setFlag(20);
    showMsg.showFlag(generic);
    Generic<Number> generic1 = new  Generic<>();
    generic1.setFlag(50);
    showMsg.showFlag(generic1);
 }
}

实时效果反馈

1.对通配符的上限的限定是指

A 实际类型只能是上限限定中所约定的类型;

B 实际类型只能是上限限定中所约定类型的子类型;

C 实际类型可以是上限限定中所约定的类型,也可以是约定类型的子类型;

D 实际类型可以是上限限定中所约定的类型,也可以是约定类型的父类型;

答案

1=>C

通配符的下限限定

对通配符的下限的限定:<? super 类型>  ?实际类型可以是下限限定中所约定的类型,也可以是约定类型的父类型;

语法结构

public void showFlag(Generic<? super Integer> generic){ }

示例

public class ShowMsg {
  public void showFlag(Generic<? super Integer> generic){
     System.out.println(generic.getFlag());
   }
}
public class Test6 {
  public static void main(String[] args) {
    ShowMsg showMsg = new ShowMsg();
    Generic<Integer> generic = new Generic<>();
    generic.setFlag(20);
    showMsg.showFlag(generic);
    Generic<Number> generic1 = new Generic<>();
    generic1.setFlag(50);
    showMsg.showFlag(generic1);
 }
}

实时效果反馈

1.对通配符的下限的限定是指

A 实际类型只能是下限限定中所约定的类型;

B 实际类型只能是下限限定中所约定类型的子类型;

C 实际类型可以是下限限定中所约定的类型,也可以是约定类型的子类型;

D 实际类型可以是下限限定中所约定的类型,也可以是约定类型的父类型;

答案

1=>D

泛型局限性和常见错误

泛型主要用于编译阶段,编译后生成的字节码class文件不包含泛型中的类型信息。 类型参数在编译后会被替换成Object,运行时虚拟机并不知道泛型。因此,使用泛型时,如下几种情况是错的:

实时效果反馈

1.如下哪个选项是错误的使用泛型?

A Generic

B Generic

C Generic

D Generic

答案

1=>D

二、容器介绍

容器简介

容器,是用来容纳物体、管理物体。生活中,我们会用到各种各样的容器。如锅碗瓢盆、箱子和包等。

程序中的“容器”也有类似的功能,用来容纳和管理数据。比如,如下新闻网站的新闻列表、教育网站的课程列表就是用“容器”来管理:

开发和学习中需要时刻和数据打交道,如何组织这些数据是我们编程中重要的内容。 我们一般通过“容器”来容纳和管理数据。事实上,我们前面所学的数组就是一种容器,可以在其中

放置对象或基本类型数据。

数组的优势:是一种简单的线性序列,可以快速地访问数组元素,效率高。如果从查询效率和类型检查的角度讲,数组是最好的。

数组的劣势:不灵活。容量需要事先定义好,不能随着需求的变化而扩容。比如:我们在一个用户管理系统中,要把今天注册的所有用户取出来,那么这样的用户有多少个?我们在写程序时是无法确定的。因此,在这里就不能使用数组。

基于数组并不能满足我们对于“管理和组织数据的需求”,所以我们需要一种更强大、更灵活、容量随时可扩的容器来装载我们的对象。 这就是我们今天要学习的容器,也叫集合(Collection)。

实时效果反馈

1.Java中容器的作用是什么?

A 容纳数据

B 处理数据

C 生产数据

D 销毁数据

答案

1=>A

容器的结构

结构图

单例集合

双例集合

实时效果反馈

1.如下哪个接口不是容器接口?

A List

B Set

C Map

D Comparable

答案

1=>D

单例集合

Collection接口介绍

Collection 表示一组对象,它是集中、收集的意思。Collection接口的两个子接口是List、Set接口。

Collection接口中定义的方法

方法  说明
boolean add(Object element) 增加元素到容器中
boolean remove(Object element) 从容器中移除元素
boolean contains(Object element) 容器中是否包含该元素
int size() 容器中元素的数量
boolean isEmpty() 容器是否为空
void clear() 清空容器中所有元素
Iterator iterator() 获得迭代器,用于遍历所有元素
boolean containsAll(Collection c) 本容器是否包含c容器中的所有元素
boolean addAll(Collection c) 将容器c中所有元素增加到本容器
boolean removeAll(Collection c) 移除本容器和容器c中都包含的元素
boolean retainAll(Collection c) 取本容器和容器c中都包含的元素,移除非交集元素
Object[] toArray() 转化成Object数组

由于List、Set是Collection的子接口,意味着所有List、Set的实现类都有上面的方法。

JDK8之后,Collection接口新增的方法(将在JDK新特性和函数式编程中介绍):

新增方法  说明
removeIf 作用是删除容器中所有满足filter指定条件的元素
stream
parallelStream
stream和parallelStream 分别返回该容器的Stream视图表示,不同之处在于parallelStream()返回并行的Stream,Stream是Java函数式编程的核心类
spliterator 可分割的迭代器,不同以往的iterator需要顺序迭代,Spliterator可以分割为若干个小的迭代器进行并行操作,可以实现多线程操作提高效率

实时效果反馈

1.如下哪个接口不是Collection接口的子接口?

A List

B Set

C Map

D Queue

答案

1=>C

List接口介绍

List接口特点

List是有序、可重复的容器。

有序:有序(元素存入集合的顺序和取出的顺序一致)。List中每个元 素都有索引标记。可以根据元素的索引标记(在List中的位置)访问 元素,从而精确控制这些元素。

可重复:List允许加入重复的元素。更确切地讲,List通常允许满足 e1.equals(e2) 的元素重复加入容器。

List接口中的常用方法

除了Collection接口中的方法,List多了一些跟顺序(索引)有关的方 法,参见下表:

ArrayList容器的基本使用

ArrayList容器的基本使用

ArrayList是List接口的实现类。是List存储特征的具体实现。 ArrayList底层是用数组实现的存储。 特点:查询效率高,增删效率 低,线程不安全。

public class ArrayListTest {
    public static void main(String[] args) {
        //实例化ArrayList容器
        List<String> list  = new ArrayList<>();
        //添加元素
        boolean flag1 = list.add("oldlu");
        boolean flag2 = list.add("itbz");
        boolean flag3 = list.add("sxt");
        boolean flag4 = list.add("sxt");
        System.out.println(flag1+"\t"+flag2+"\t"+flag3+"\t"+flag4);
        //删除元素
        boolean flag4 = list.remove("oldlu");
        System.out.println(flag4);
        //获取容器中元素的个数
        int size = list.size();
        System.out.println(size);
        //判断容器是否为空
        boolean empty = list.isEmpty();
        System.out.println(empty);
        //容器中是否包含指定的元素
        boolean value = list.contains("itbz");
        System.out.println(value);
        //清空容器
        list.clear();
        Object[] objects1 = list.toArray();
        System.out.println(Arrays.toString(objects1));
   }
}

ArrayList容器的索引操作

public class ArrayListTest2 {
    public static void main(String[] args) {
        //实例化容器
        List<String> list = new ArrayList<>();
        //添加元素
        list.add("oldlu");
        list.add("itbz");
        //向指定位置添加元素
        list.add(0,"sxt");
        System.out.println("获取元素");
        String value1 = list.get(0);
        System.out.println(value1);
        System.out.println("获取所有元素方式一");
        //使用普通for循环
        for(int i=0;i<list.size();i++){
            System.out.println(list.get(i));
         }
        System.out.println("获取所有元素方式二");
        //使用Foreach循环
        for(String str:list){
            System.out.println(str);
       }
       System.out.println("元素替换");
        list.set(1,"kevin");
        for(String str:list){
            System.out.println(str);
       }
        System.out.println("根据索引位置删除元素);
        String value2 = list.remove(1);
        System.out.println(value2);
        System.out.println("----------------");
        for(String str:list){
            System.out.println(str);
       }
        System.out.println("查找元素第一次出现的位置");
        int value3 = list.indexOf("sxt");
        System.out.println(value3);
        System.out.println("查找元素最后一次出现的位置");
        list.add("sxt");
        for(String str:list){
            System.out.println(str);
       }
        int value4 = list.lastIndexOf("sxt");
        System.out.println(value4);
   }
}

ArrayList的并集、交集、差集

并集

//并集操作:将另一个容器中的元素添加到当前容器中
        List<String> a  = new ArrayList<>();
        a.add("a");
        a.add("b");
        a.add("c");
        List<String> b = new ArrayList<>();
        b.add("a");
        b.add("b");
        b.add("c");
        //a并集b
        a.addAll(b);
        for(String str :a){
            System.out.println(str);
       }

交集

//交集操作:保留相同的,删除不同的
        List<String> a1  = new ArrayList<>();
        a1.add("a");
        a1.add("b");
        a1.add("c");
        List<String> b1 = new ArrayList<>();
        b1.add("a");
        b1.add("d");
        b1.add("e");
        //交集操作
        a1.retainAll(b1);
        for(String str :a1){
            System.out.println(str);
       }

差集

//差集操作:保留不同的,删除相同的
        List<String> a2  = new ArrayList<>();
        a2.add("a");
        a2.add("b");
        a2.add("c");
        List<String> b2= new ArrayList<>();
        b2.add("b");
        b2.add("c");
        b2.add("d");
        a2.removeAll(b2);
        for(String str :a2){
            System.out.println(str);
       }

ArrayList源码分析

ArrayList底层是用数组实现的存储。

成员变量

/**
* Default initial capacity.
*/
   private static final int DEFAULT_CAPACITY = 10;
/**
* The array buffer into which the elements of the ArrayList are stored.
/**
* The array buffer into which the elements of the ArrayList are stored.
* The capacity of the ArrayList is the length of this array buffer. Any
* empty ArrayList with elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA
* will be expanded to DEFAULT_CAPACITY when the first element is added.
*/
transient Object[] elementData; // nonprivate to simplify nested class access
/**
* The size of the ArrayList (the number of elements it contains).
*
* @serial
*/
private int size;

数组初始大小

/**
* Default initial capacity.
*/
private static final int DEFAULT_CAPACITY = 10;

添加元素

/**
* Appends the specified element to the end of this list.
*
* @param e element to be appended to this list
* @return <tt>true</tt> (as specified by {@link Collection#add})
*/
public boolean add(E e) {
    ensureCapacityInternal(size + 1);  //Increments modCount!!
    elementData[size++] = e;
    return true;
}

判断数组是否扩容

//容量检查
private void ensureCapacityInternal(int minCapacity) {  
    ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
//容量确认
private void ensureExplicitCapacity(int minCapacity) {
    modCount++;
    //判断是否需要扩容,数组中的元素个数-数组长度,如果大于0表明需要扩容
    if (minCapacity - elementData.length > 0)
        grow(minCapacity);
}

数组扩容

/**
* Increases the capacity to ensure that it can hold at least the
* number of elements specified by the minimum capacity argument.
*
* @param minCapacity the desired minimum capacity
*/
private void grow(int minCapacity) {
  // overflow-conscious code
    int oldCapacity = elementData.length;
  //扩容1.5倍
    int newCapacity = oldCapacity + (oldCapacity >> 1);
    if (newCapacity - minCapacity < 0)
        newCapacity = minCapacity;
    if (newCapacity - MAX_ARRAY_SIZE > 0)
        newCapacity = hugeCapacity(minCapacity);
    // minCapacity is usually close to size, so this is a win:
    elementData = Arrays.copyOf(elementData,newCapacity);
}

Vector容器的基本使用

Vector底层是用数组实现的,相关的方法都加了同步检查,因此“线 程安全,效率低”。 比如,indexOf方法就增加了synchronized同步 标记。

Vector的使用

Vector的使用与ArrayList是相同的,因为他们都实现了List接口, 对List接口中的抽象方法做了具体实现。

public class VectorTest {
    public static void main(String[] args) {
        //实例化Vector
        List<String> v = new Vector<>();
        v.add("a");
        v.add("b");
        v.add("a");
        for(int i=0;i<v.size();i++){
            System.out.println(v.get(i));
       }
        System.out.println("----------------------");
        for(String str:v){
            System.out.println(str);
       }
   }
}

Vector源码分析

成员变量

/**
* The array buffer into which the components of the vector are
* stored. The capacity of the vector is the length of this array buffer,
* and is at least large enough to contain all the vector's elements.
*
* <p>Any array elements following the last element in the Vector are null.
*
* @serial
*/
protected Object[] elementData;
    /**
     * The number of valid components in this {@code Vector} object.
     * Components {@code elementData[0]} through
     * {@code elementData[elementCount-1]} are the actual items.
     *
     * @serial
     */
protected int elementCount;
    /**
     * The amount by which the capacity of the vector is automatically
     * incremented when its size becomes greater than its capacity. If
     * the capacity increment is less than or equal to zero, the capacity
     * of the vector is doubled each time it needs to grow.
     *
     * @serial
     */
protected int capacityIncrement;

构造方法

public Vector() {
    this(10);
}

添加元素

/**
* Appends the specified element to the end of this Vector.
*
* @param e element to be appended to this Vector
* @return {@code true} (as specified by {@link Collection#add})
* @since 1.2
*/
public synchronized boolean add(E e) {
    modCount++;
    ensureCapacityHelper(elementCount + 1);
    elementData[elementCount++] = e;
    return true;
}

数组扩容

/**
* This implements the unsynchronized semantics of ensureCapacity.
* Synchronized methods in this class can internally call this
* method for ensuring capacity without incurring the cost of an
* extra synchronization.
*
* @see #ensureCapacity(int)
*/
private void ensureCapacityHelper(int minCapacity) {
    // overflow-conscious code
   //判断是否需要扩容,数组中的元素个数-数组长度,如果大于0表明需要扩容
if (minCapacity - elementData.length >0)
        grow(minCapacity);
}
private void grow(int minCapacity) {
    // overflow-conscious code
    int oldCapacity = elementData.length;
   //扩容2倍
    int newCapacity = oldCapacity + ((capacityIncrement > 0) ? capacityIncrement : oldCapacity);
    if (newCapacity - minCapacity < 0)
        newCapacity = minCapacity;
    if (newCapacity - MAX_ARRAY_SIZE > 0)
        newCapacity = hugeCapacity(minCapacity);
    elementData = Arrays.copyOf(elementData, newCapacity);
}
目录
相关文章
|
2天前
|
Cloud Native 持续交付 Docker
Docker容器化技术:从入门到实践
Docker容器化技术:从入门到实践
|
9天前
|
Cloud Native 持续交付 云计算
云原生入门指南:从容器到微服务
【10月更文挑战第28天】在数字化转型的浪潮中,云原生技术成为推动现代软件开发的关键力量。本篇文章将带你了解云原生的基本概念,探索它如何通过容器化、微服务架构以及持续集成和持续部署(CI/CD)的实践来提升应用的可伸缩性、灵活性和可靠性。你将学习到如何利用这些技术构建和部署在云端高效运行的应用,并理解它们对DevOps文化的贡献。
27 2
|
14天前
|
运维 Kubernetes Cloud Native
云原生入门:Kubernetes和容器化的未来
【10月更文挑战第23天】本文将带你走进云原生的世界,探索Kubernetes如何成为现代软件部署的心脏。我们将一起揭开容器化技术的神秘面纱,了解它如何改变软件开发和运维的方式。通过实际的代码示例,你将看到理论与实践的结合,感受到云原生技术带来的革命性影响。无论你是初学者还是有经验的开发者,这篇文章都将为你开启一段新的旅程。让我们一起踏上这段探索之旅,解锁云原生技术的力量吧!
|
20天前
|
Ubuntu Shell 开发者
Docker入门:轻松开始容器化之旅
【10月更文挑战第17天】Docker 是一种开源的应用容器引擎,它让开发者能够“一次构建、到处运行”。Docker 通过容器化技术将应用程序及其依赖打包在一起,从而确保应用在任何环境中都能一致地运行。本文将为新手用户提供一个全面的Docker入门指南,包括基本概念、优势、安装配置以及如何创建和管理容器。
41 2
|
27天前
|
存储 运维 云计算
探索Docker容器化:从入门到实践
在这个快速发展的云计算时代,Docker容器化技术正在改变应用的开发、部署和管理方式。本文旨在为初学者提供一个关于Docker的全面入门指南,并通过实践案例展示Docker在实际开发中的应用。我们将一起了解Docker的核心概念、基本操作、网络和存储,以及如何构建和部署一个简单的Web应用。无论你是开发者还是运维人员,本文都会帮助你快速掌握Docker的核心技能。
|
1月前
|
Kubernetes Linux 持续交付
docker容器学习
【10月更文挑战第1天】
35 1
|
1月前
|
Kubernetes Cloud Native Docker
云原生时代的容器化实践:Docker与Kubernetes入门
【9月更文挑战第30天】在云计算的浪潮中,云原生技术正以前所未有的速度重塑着软件开发和运维领域。本文将通过深入浅出的方式,带你了解云原生的核心组件——Docker容器和Kubernetes集群,并探索它们如何助力现代应用的构建、部署和管理。从Docker的基本命令到Kubernetes的资源调度,我们将一起开启云原生技术的奇妙之旅。
|
2月前
|
Kubernetes API Docker
跟着iLogtail学习容器运行时与K8s下日志采集方案
iLogtail 作为开源可观测数据采集器,对 Kubernetes 环境下日志采集有着非常好的支持,本文跟随 iLogtail 的脚步,了解容器运行时与 K8s 下日志数据采集原理。
|
1月前
|
运维 Kubernetes Cloud Native
云原生时代的容器编排:Kubernetes入门与实践
【10月更文挑战第4天】在云计算的浪潮中,云原生技术以其敏捷、可扩展和高效的特点引领着软件开发的新趋势。作为云原生生态中的关键组件,Kubernetes(通常被称为K8s)已成为容器编排的事实标准。本文将深入浅出地介绍Kubernetes的基本概念,并通过实际案例引导读者理解如何利用Kubernetes进行高效的容器管理和服务部署。无论你是初学者还是有一定经验的开发者,本文都将为你打开云原生世界的大门,并助你一臂之力在云原生时代乘风破浪。
|
1月前
|
Ubuntu Linux 应用服务中间件
Docker容器入门实战
Docker容器入门实战
下一篇
无影云桌面