Java入门-java的集合框架

集合概念

集合,有时也称作容器(Container), 是对象的持有者,它们可以有助于高效访问的方式存储的组织对象。以生活中的案例为例: 集合就像装衣服的柜子,衣服就是集合中的元素。

img

集合框架图

image-20240527172334115

Collection中每次操作的都是一个对象,如果要操作一对对象就必须使用Map,Map中所有的对象都按照key->value形式保存,也称二元偶对象。Iterator(迭代器)不是一个集合,它是一种用于访问集合的方法。Collections 类是 Java 提供的一个操作 Set、List 和 Map 等集合的工具类。

泛型

泛型概念

把类型明确的工作推迟到创建对象或调用方法的时候才去明确的特殊的类型。

泛型一般表示为<E>

例如:

public class ArrayList<E> implements List<E>{}

这个ArrayList类中用到的类,用E替代(泛型), 当创建对象时才明确它的类型。

new ArrayList<String>(); //创建对象时泛型明确为String类型

为什么使用泛型?

  • 使代码更加简洁

  • 使程序更加健壮

  • 提高可读性和稳定性

程序案例:

List<User> users = new ArrayList<>();
User user = new User();
users.add(user); 

如程序演示:使用泛型定义了对象使用类型为Dog类型,如果使用其它类型编译器检查则会报错,早检查出错增强程序的健壮性。

泛型的擦除

java的一个特性,在运行时,java不会保留泛型。

Java 泛型的参数只可以代表类,不能代表个别对象。由于Java泛型的类型参数之实际类型在编译时会被消除,所以无法在运行时得知其类型参数的类型。Java 编译器在编译泛型时会自动加入类型转换的编码,故运行速度不会因为使用泛型而加快。

泛型是Java SE 1.5的新特性,泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。这种参数类型可以用在类、接口和方法的创建中,分别称为泛型类、泛型接口、泛型方法。 Java语言引入泛型的好处是安全简单。

泛型的好处是在编译的时候检查类型安全,并且所有的强制转换都是自动和隐式的,以提高代码的重用率。

通配符泛型

无边界通配符: 例如List<?> , ? 表示不确定的java类型。

固定上边界通配符: 例如List<? extends Car> ,表示指定类的子类,Car即为上边界。

固定下边界通配符: 例如List<? super Car>,表示Car的父类,Car即为下边界。

Collection接口

The root interface in the collection hierarchy。

集合层次结构的根接口。定义了集合的常用api。

image-20240527172736069

List接口

List接口是Collection接口的子接口。有序的集合,存储元素和取出元素的顺序是一致的(存储abc则取出abc)有索引,包含了一些带索引的方法允许存储重复的元素。

ArrayList

ArrayList类特性

底层由动态数组构成,即数组的长度可变。

ArrayList的类层次结构

image-20240526175020435

image-20240526175048180

image-20240526175107499

ArrayList的属性

数组的初始长度为10

private static final int DEFAULT_CAPACITY = 10;private static final Object[] EMPTY_ELEMENTDATA ={};//第一次添加元素时知道该 elementData 从空的构造函数还是有参构造函数被初始化的。以便确认如何扩容。private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA ={};transient Object[] elementData;// non-private to simplify nested class accessprivate int size;//数组最大的分配容量private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
构造方法

无参构造方法

当使用默认构造方法时,对象数组指向DEFAULTCAPACITY_EMPTY_ELEMENTDATA容量为0,当第一次添加数据时,将数组的长度扩展为默认大小DEFAULT_CAPACITY。

源码分析:

public ArrayList() {this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}

有参构造方法 初始化数组的长度

源码分析:

public ArrayList(int initialCapacity) {if(initialCapacity > 0) {this.elementData = new Object[initialCapacity];}else if (initialCapacity == 0) {this.elementData = EMPTY_ELEMENTDATA;} else {throw new  IllegalArgumentException("Illegal Capacity: "+ initialCapacity);}
}
添加元素
add(E e):添加 元素List\<Integer> list = new ArrayList<>();list.add(1);

源码分析:

public boolean  add(E e) {ensureCapacityInternal(size + 1);  // 确认容量是否足够elementData[size++] = e;return true ;}

确认最小空间

private void  ensureCapacityInternal( int  minCapacity) {ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}

初始化数组空间大小

private static int  calculateCapacity(Object[] elementData, int minCapacity){//如果是空数组,则将数组长度变为DEFAULT_CAPACITY=10;if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {return Math.max(DEFAULT_CAPACITY\*, minCapacity);}return minCapacity;
}

实现数组的扩容处理

private void ensureExplicitCapacity(int minCapacity) {//如果当集合容量+1 > 数组的长度,那么数组要进行扩容if (minCapacity - elementData.length > 0) grow(minCapacity);
}private void grow(int minCapacity) {int oldCapacity = elementData.length;int newCapacity = oldCapacity + (oldCapacity >> 1); //扩容1.5倍if (newCapacity - minCapacity < 0)    newCapacity = minCapacity;if (newCapacity - *MAX_ARRAY_SIZE\* > 0) //超过了数组的最大指newCapacity = *hugeCapacity*(minCapacity);elementData = Arrays.*copyOf*(elementData, newCapacity); //数组扩容}
删除元素remove(int index),根据位置删除:

img

list.remove(1); //删除元素-根据位置删除 

源码分析:

public E remove(int index) {......E oldValue = elementData(index); //删除之前获取旧数据int numMoved = size - index - 1; //要移动的数组元素数量if (numMoved > 0)System.arraycopy(elementData, index+1, elementData, index,numMoved);elementData[--size] = null; //将最后一个元素置为null,数组容量-1return oldValue;
}
删除元素:根据对象内容删除

删除的对象需要实现equals()方法

boolean remove(Object o) //根据对象删除

List<String> list = new ArrayList<>();
list.add("apple");
list.add("banana");
list.add("orange");
list.remove("banana");

源码分析:

我们发现删除时需要调用元素的equals()方法。

public boolean remove(Object o) {if (o == null) {for (int index = 0; index < size; index++)if (elementData[index] == null) {fastRemove(index);return true;}} else { for (int index = 0; index < size; index++)if (o.equals(elementData[index])) {//使用对象的equals方法比较fastRemove(index);return true;}}return false;
}

集合中的类型是String,则使用String中的equals()方法,如果为自定义类型,需要重写对象的equals()方法。

/*** String类中重写了equals()方法*/
public boolean equals(Object anObject) {if (this == anObject) {return true;}if (anObject instanceof String) {String anotherString = (String)anObject;int n = value.length;if (n == anotherString.value.length) {char v1[] = value;char v2[] = anotherString.value;int i = 0;while (n-- != 0) {if (v1[i] != v2[i])return false;i++;}return true;}}return false;}

删除元素源码分析:

private void fastRemove(int index) {int numMoved = size - index - 1;if (numMoved > 0)System.arraycopy(elementData, index+1, elementData, index,numMoved);elementData[--size] = null; // clear to let GC do its work
}
修改元素

E set(int index, E e) 修改元素\

list.set(1, "orange");

源码分析:

public E set(int index, E element) {E oldValue = elementData(index);elementData[index] = element;return oldValue;
}
查询元素

E get(int index) 查询元素

list.get(3);

源码分析:

public E get(int index) {rangeCheck(index);return elementData(index);
} 

LinkedList

什么是链表?

逻辑上连续,空间上不联系,如下图车厢和前后两个车厢相连(双向链表)。

img

如何定义链表(双向链表)
定义节点
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;}
}
2头节点即链表的第一个节点。
transient Node<E> first;
尾节点即链表的最后一个节点
 transient Node<E> last;
设计双向链表(LinkedList的实现)

boolean add(E e) //添加节点

源码分析:

public boolean add(E e) {linkLast(e);return true;
}void linkLast(E e) {final Node<E> l = last; //记录尾节点final Node<E> newNode = new Node<>(l, e, null);last = newNode;if (l == null) //链表为空,新节点即为第一个节点first = newNode; //头节点指向新节点elsel.next = newNode; //链表不为空,则尾节点连接新节点size++;:
}

boolean remove(Object o) 删除节点

源码分析:

public boolean remove(Object o) {if (o == null) {for (Node<E> x = first; x != null; x = x.next) {if (x.item == null) {unlink(x);return true;}}} else {for (Node<E> x = first; x != null; x = x.next) {if (o.equals(x.item)) {unlink(x);return true;}}}return false;
}
E unlink(Node<E> x) { //x为要删除的节点对象final E element = x.item;
final Node<E> next = x.next; 
final Node<E> prev = x.prev;if (prev == null) { //删除头节点first = next;
} else {prev.next = next;//删除节点的前一个节点连接后一个节点x.prev = null;
}
if (next == null) {//删除尾节点last = prev;} else {next.prev = prev;//删除节点的后一个节点连接前一个节点x.next = null;
}
x.item = null;
size--;
return element;
}

E set(int index, E element) 修改节点信息

源码分析:

public E set(int index, E element){
Node<E> x = node(index);
E oldVal = x.item;
x.item = element;
return oldVal;
}

public E get(int index) 查询某个节点信息

源码分析:

public E get(int index) {return node(index).item;
}Node<E> node(int index) {
if (index < (size >> 1)) {Node<E> x = first;for (int i = 0; i < index; i++) x = x.next;return x;
} else {Node<E> x = last;for (int i = size - 1; i > index; i--) x = x.prev;return x;}
}

Vector类

Vector 类实现了一个动态数组。。

Vector的类的层次结构

public class Vector<E>extends AbstractList<E>implements List<E>, RandomAccess, Cloneable, java.io.Serializable

Vector的api

public synchronized boolean add(E e):添加
public synchronized boolean add(E e) {ensureCapacityHelper(elementCount + 1);elementData[elementCount++] = e;return true;
}
public synchronized E remove(int index): 删除
public synchronized E set(int index, E element):修改
public synchronized E get(int index):查询
程序案例:
Vector<String> v = new Vector<>();		
v.add("apple");
v.add("orange");
v.add("banana"); 
v.remove(1);	
v.set(0, "strawberry");		
String f = v.get(1);		
System.*out\*.println(f);
System.*out\*.println(v);

程序运行结果:

banana
[strawberry, banana]

Iterator接口实现元素遍历

迭代器是一种设计模式,它是一个对象,它可以遍历并选择序列中的对象,而开发人员不需要了解该序列的底层结构。迭代器通常被称为“轻量级”对象,因为创建它的代价小。

程序案例:

List<String> l = new ArrayList();
l.add("apple");
l.add("orange");
l.add("banana");
for (Iterator<String> iter = l.iterator(); iter.hasNext();) {String str = (String) iter.next();System.*out\*.println(str);
}

Stack类

限定仅在表尾进行插入或删除操作的线性表,表尾—栈顶,表头—栈底,不含元素的空表称空栈。

img\

类的结构

image-20240527174910576

Stack常用API

image-20240527175001995

程序案例:

Stack<Integer> stack = new Stack<>();
stack.push(6);
stack.push(2);
stack.push(5);
stack.push(1);

Queue接口

队列(简称作队)也是一种特殊的线性表,队列的数据元素以及数据元素间的逻辑关系和线性表完全相同,其差别是线性表允许在任意位置插入和删除,而队列只允许在其一端进行插入操作在其另一端进行删除操作。队列中允许进行插入操作的一端称为队尾,允许进行删除操作的一端称为队头。队列的插入操作通常称作入队列,队列的删除操作通常称作出队列。

img

接口结构

image-20240527175136505

Queue常用API

image-20240527175204627

Set接口

set接口是继承自Collection的子接口。

Set接口特性

特点是元素不重复,存储无序。在set接口的实现类中添加重复元素是不会成功的,判断两个元素是否重复根据元素类重写的hashCode()和equals()方法。

Set接口的实现类 HashSet

image-20240527175308483

常用api:

boolean add(E e)boolean remove(Object o)/*底层使用map,删除key*/public boolean remove(Object o) {return map.remove(o)==*PRESENT\*;
}

其它Set接口的实现类

TreeSet<E>

LinkedHashSet<E>

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

android-mvp模式

mvvm可以理解成使用databing的mvp模式&#xff0c;modleview 通过接口让view和Presenter层解耦 从图中就可以看出&#xff0c;最明显的差别就是view层和model层不再相互可知&#xff0c;完全的解耦&#xff0c;取而代之的presenter层充当了桥梁的作用&#xff0c;用于操作view…

56. UE5 RPG 给敌人添加AI实现跟随玩家

在这一篇里&#xff0c;我们要实现一下敌人的AI&#xff0c;敌人也需要一系列的行为&#xff0c;比如朝向英雄攻击&#xff0c;移动&#xff0c;在满足条件时施放技能。这些敌人的行为可以通过使用UE的内置的AI系统去实现。 在UE里&#xff0c;只要是基于Character类创建的蓝图…

java欢迪迈手机商城设计与实现源码(springboot+vue+mysql)

风定落花生&#xff0c;歌声逐流水&#xff0c;大家好我是风歌&#xff0c;混迹在java圈的辛苦码农。今天要和大家聊的是一款基于springboot的欢迪迈手机商城设计与实现。项目源码以及部署相关请联系风歌&#xff0c;文末附上联系信息 。 项目简介&#xff1a; 欢迪迈手机商城…

D - Permutation Subsequence(AtCoder Beginner Contest 352)

题目链接: D - Permutation Subsequence (atcoder.jp) 题目大意&#xff1a; 分析&#xff1a; 相对于是记录一下每个数的位置 然后再长度为k的区间进行移动 然后看最大的pos和最小的pos的最小值是多少 有点类似于滑动窗口 用到了java里面的 TreeSet和Map TreeSet存的是数…

【C语言】结构体内存对齐:热门面试话题

&#x1f525;引言 书接上文&#xff0c;我们了解关于结构体的基本知识&#xff0c;这篇将深入剖析结构体中一个重要的知识点:内存对齐 关于内存对齐是属于热门面试话题&#xff0c;对此单独放在一篇来分享 &#x1f308;个人主页&#xff1a;是店小二呀 &#x1f308;C语言笔记…

Docker Portainer使用

Portainer是什么 Docker Portainer是一个轻量级的 Web UI 管理界面,可以用来管理Docker环境。它提供了一个直观的控制台,用户可以通过它来管理Docker主机、容器、网络、卷等Docker资源。 Portainer的主要功能和特点包括: 容器管理:可以查看、启动、停止、删除容器,以及查看容器…

计算机毕业设计 | springboot+vue房屋租赁管理系统(附源码)

1&#xff0c;绪论 1.1 课题来源 随着社会的不断发展以及大家生活水平的提高&#xff0c;越来越多的年轻人选择在大城市发展。在大城市发展就意味着要在外面有一处安身的地方。在租房的过程中&#xff0c;大家也面临着各种各样的问题&#xff0c;比如需要费时费力去现场看房&…

host修改

前言 想要修改 hosts 文件&#xff0c;您需要具有对系统文件的适当访问权限&#xff0c;并且知道如何编辑文本文件。hosts 文件是一个用于域名解析的本地文件&#xff0c;它允许您为特定的 IP 地址指定主机名。 以下是在不同操作系统中修改 hosts 文件的步骤&#xff1a; 一、…

项目集成SkyWalking,基于k8s搭建

一、搭建SkyWalking 官方文档&#xff08;英文&#xff09;&#xff1a;skywalking/docs at master apache/skywalking 中文可以使用&#xff1a;GitHub - SkyAPM/document-cn-translation-of-skywalking: [已过期,请使用官网AI文档] The CN translation version of Apache…

【qt】自定义代理类

自定义代理类 一.应用场景二.创建自定义代理类1.创建一个类2.共有继承父类3.添加宏4.初始化父类5.拿到我们需要重写的虚函数 三.实现父类的4个虚函数1.创建代理组件2.设置代理组件数据3.设置模型数据4.跟新代理组件的位置 四.使用代理类1.头文件2.私有成员3.视图设置代理 五.其…

Web上机:JSP+Servlet+JDBC的交互流程

目录 需求与设计 基础需求&#xff1a; 项目结构&#xff1a; 项目逻辑&#xff1a; 运行图示&#xff1a; 代码实现 Login.jsp InsertServlet SelectServlet Table.jsp user mysql表结构 Web开发技术迭代速度日新月异&#xff0c;对于技术的更新往往是基于底层一…

基于Python+flask+echarts的气象数据采集与分析系统,可实现lstm算法进行预测

背景 基于PythonFlaskEcharts的气象数据采集与分析系统结合了强大的数据处理能力和可视化展示技术&#xff0c;旨在实现对气象数据的实时采集、存储和分析。通过Python编程语言实现数据采集模块&#xff0c;利用Flask框架搭建后端系统&#xff0c;实现数据处理、存储和分析功能…

Python小游戏——俄罗斯方块

文章目录 项目介绍环境配置代码设计思路1.初始化和导入库&#xff1a;2.定义颜色和屏幕尺寸&#xff1a;3.定义游戏逻辑&#xff1a;4.游戏循环&#xff1a; 源代码效果图 项目介绍 俄罗斯方块游戏是一款经典的益智游戏&#xff0c;玩家通过旋转和移动各种形状的方块&#xff…

深入剖析—【服务器硬件】与【Nginx配置】:从基础到实战

服务器硬件部分&#xff1a; Processor (CPU)&#xff1a;服务器的计算核心&#xff0c;负责处理数据和执行程序。Memory (RAM)&#xff1a;用于暂时存储和快速访问数据&#xff0c;决定了系统的运行速度和并发处理能力。Storage (HDD/SSD)&#xff1a;长期存储数据的设备&…

爱设计AiPPT.cn赵充:营销工作的AI进化

爱设计&AiPPT.cn是一家 AIGC 数字科技企业&#xff0c;致力于打造「下一代个人与组织的 Ai 工作站」 。目前旗下产品包括AiPPT.cn、爱设计AIGC 内容中台、365 编辑器、爱设计在线设计工具、AiH5 等超过 10 余款应用 AI 能力的内容创作工具。日前&#xff0c;爱设计&AiP…

期货学习笔记-横盘行情学习1

横盘行情的特征及分类 横盘行情的概念 横盘行情时中继形态的一种&#xff0c;一般常出现在大涨或大跌之后出现横盘行情是对当前趋势行情的修正&#xff0c;是对市场零散筹码的清理&#xff0c;是为了集中筹码更便于后期行情的展开 横盘行情的特征 1.水平运动&#xff1a;该…

从零自制docker-15-【实现 mydocker run -d 支持后台运行容器】

文章目录 实现目的莫名奇妙的问题对之前upper层出现root补充对run某些命令出现找不到文件或目录的原因代码效果 实现目的 docker run -d时容器在后台运行&#xff0c;而不会进入命令行交互形式 首先是需要添加-d选项然后设置当添加-d选项时候主进程不会等待子进程&#xff0c…

从Python代码到pip包:打包Python项目

大家好&#xff0c;在软件开发的世界中&#xff0c;共享和重用代码是至关重要的。Python社区为我们提供了丰富的资源&#xff0c;使得我们能够轻松地与他人分享我们的工作&#xff0c;并从他人的工作中受益。将代码打包成pip包&#xff08;Python包管理器&#xff09;是一种常见…

Moto和Inter字节序

inter: 低地址按照start_bit位放低字节依次往高字节填充 MotoLsb: 低地址按照start_bit位放高字节&#xff0c;依次往低字节填充MotoMsb&#xff1a;高字节按照start_bit位放低地址&#xff0c;依次往高字节填充

uni-app实现页面之间的跳转传参(八)

界面之间的参数传递在 开发中经常会用到,这节主要将一下uni-app开发应用是的传参情况。如下图所示,我的一级界面将点检分成三类:日点检、周点检和年保养;在点击相应的会导航到相应的功能。 在uni-app中常用的方法有uni.navigateTo(OBJECT)、uni.redirectTo(OBJECT);简单的…