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 access

private 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,数组容量-1
  return 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; //头节点指向新节点
   else
     l.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>

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

智慧林业云巡平台 客户端和移动端(支持语音和视频)自动定位巡护,后端离线路线监测

目前现状 无法客观、方便地掌握护林员的到位情况&#xff0c;因而无法有效地保证巡护人员按计划要求&#xff0c;按时按周期对所负责的林区开展巡护&#xff0c;使巡护工作的质量得不到保证。遇到火情、乱砍滥伐等灾情时无法及时上报处理&#xff0c;现场状况、位置等信息描述…

pycharm打开服务器(linux)上的项目

先在本地打开项目 一、项目文件配置 tools-deployment-configuration 新增一个sftp连接 测试服务器是否可以连通 mappings中设置本地路径和服务器上的路径 二、环境配置 先参考文章 复现论文的conda环境&#xff08;win和联网、离线linux&#xff09;_conda复现环境-CSDN博…

Qt pro工程文件编写汇总(区分debug和release、32位和64位的方法,编译输出目录等)

前言&#xff1a; 从事qt开发已经好几年了&#xff0c;但有关pro编写的一些细节问题一直没有一个很好的梳理汇总——因为实际工作开发中&#xff0c;往往只需要编译特定版本的软件&#xff08;例如32位release版本&#xff09;&#xff0c;项目创建好后并设置好编译路径&#x…

美团Java社招面试题真题,最新面试题

如何处理Java中的内存泄露&#xff1f; 1、识别泄露&#xff1a; 使用内存分析工具&#xff08;如Eclipse Memory Analyzer Tool、VisualVM&#xff09;来识别内存泄露的源头。 2、代码审查&#xff1a; 定期进行代码审查&#xff0c;关注静态集合类属性和监听器注册等常见内…

逻辑分析仪的调试使用

调试软件下载&#xff1a;点击跳转 一、接线 逻辑分析仪 设备 GND --- GND CHX&#xff08;数据通道&#xff09; --- 通信引脚 二、数据采集 图中两个可以选择数字大小的地方分别表示 采样深度 &#xff08;10M Samples&a…

Swift 类和结构体

类和结构体 一、结构体和类对比1、类型定义的语法2、结构体和类的实例3、属性访问4、结构体类型的成员逐一构造器 二、结构体和枚举是值类型三、类是引用类型1、恒等运算符2、指针 结构体和类作为一种通用而又灵活的结构&#xff0c;成为了人们构建代码的基础。你可以使用定义常…

【全开源】活动报名表单系统(ThinkPHP+Uniapp+uView)

轻松构建高效报名平台 一、引言 随着线上活动的日益增多&#xff0c;一个高效、易用的活动报名表单系统成为了举办各类活动的必备工具。为了满足不同组织和个人的需求&#xff0c;我们推出了功能强大的“活动报名表单系统源码”。本文将为您详细介绍该源码的特点、功能以及使…

xml篇---提取VOC格式的坐标,并按照cameraID进行排序(二)

xml篇—提取VOC格式的坐标&#xff0c;并按照cameraID进行排序&#xff08;二&#xff09; import os import xml.etree.ElementTree as ETdef parse_xml(xml_file):tree ET.parse(xml_file)root tree.getroot()objects {}for obj in root.findall(object):name obj.find(…

使用ResNet-50训练自己的数据集(花的种类)

1.数据集处理 具体操作 1.把不同类别的花&#xff08;或者自己数据集的不同类别&#xff09;放在不同的文件夹下 2.文件夹名字是花朵类别 代码预处理 # 对数据集进行处理 import os from shutil import copy import randomdef mkfile(file):if not os.path.exists(file):os…

简易计算器

前言 简易计算器&#xff0c;旨在实现一个简单的计算器功能。 整形&#xff0c;浮点型数据的加减乘除运算&#xff1b;数据的统计(如文件中某字符的出现频数)&#xff1b;期望&#xff0c;方程运算&#xff1b;平均数&#xff0c;最小值&#xff0c;最大值&#xff0c;中位数…

每日5题Day11 - LeetCode 51 - 55

每一步向前都是向自己的梦想更近一步&#xff0c;坚持不懈&#xff0c;勇往直前&#xff01; 第一题&#xff1a;51. N 皇后 - 力扣&#xff08;LeetCode&#xff09; class Solution {public List<List<String>> solveNQueens(int n) {List<List<String>…

揭秘订单排队模式:社交电商新策略

随着移动互联网的蓬勃发展&#xff0c;社交电商正以其独特的魅力席卷全球。据权威机构预测&#xff0c;到2024年&#xff0c;全球社交电商市场规模有望达到惊人的2.8万亿美元。面对如此庞大的市场蛋糕&#xff0c;如何精准把握机遇&#xff0c;实现业务的跨越式增长&#xff0c…

SQL157 平均播放进度大于60%的视频类别

描述 用户-视频互动表tb_user_video_log iduidvideo_idstart_timeend_timeif_followif_likeif_retweetcomment_id110120012021-10-01 10:00:002021-10-01 10:00:30011NULL210220012021-10-01 10:00:002021-10-01 10:00:21001NULL310320012021-10-01 11:00:502021-10-01 11:01…

强大的医院绩效考核管理系统源码,支持行业内所有绩效方案,且每步核算都可自主进行方案的新建、调整。

医院绩效考核管理系统是采用B/S架构模式设计、使用JAVA语言开发、后台使用MySql数据库进行管理的一整套计算机应用软件源码。 系统和his系统进行对接&#xff0c;按照设定周期&#xff0c;从his系统获取医院科室和医生、护士、其他人员工作量&#xff0c;对没有录入信息化系统…

定时调度任务——kettle开发22

一、流查询 流查询在查询前把数据加载到内存中&#xff0c;并且只能进行等值查询。 流查询的操作包括指定数据源&#xff0c;即我们将数据进行流查询的数据源头&#xff0c;如下图所示流查询的数据源是我们的Excel输入-departments&#xff0c;然后我们还需要指定我们进行流查…

手机远程协助,3个方法,开启沟通新篇章

已经不仅仅是一个通讯工具&#xff0c;更是一个多功能的魔法棒。它轻轻一挥&#xff0c;就能让我们跨越千山万水&#xff0c;与亲朋好友、合作伙伴进行亲密无间的交流。今天&#xff0c;就让我们一起探讨如何利用手机远程协助的三大法宝&#xff0c;开启沟通的新篇章&#xff0…

二叉树——堆的实现

一.前言 前面我们讲解了二叉树的概念以及二叉树的存储结构&#xff1a;https://blog.csdn.net/yiqingaa/article/details/139224974?spm1001.2014.3001.5502 今天我们主要讲讲二叉树的存储结构&#xff0c;以及堆的实现。 二.正文 1.二叉树的顺序结构及实现 1.1二叉树的顺序…

手动操作很麻烦?试试这个自动加好友神器吧!

你是不是也觉得手动逐一输入号码或是微信号&#xff0c;再搜索添加很麻烦&#xff1f;试试这个自动加好友神器——个微管理系统&#xff0c;帮助你省去繁琐的手工操作&#xff0c;节省时间和精力。 首先&#xff0c;在系统上登录微信号&#xff0c;无论你有多少个微信号&#…

服务器重装系统与磁盘操作

诱因&#xff1a;服务器原来装的EXSI&#xff0c;现在要重装一个ubuntu server&#xff0c;出现了下面一些问题&#xff0c;在此记录一下。 目录 1、过程中出现的问题&#xff08;2024.5.26&#xff09;1.1 问题1&#xff1a;如何磨掉原来的ESXI&#xff1f;1.2 问题2&#xf…

【Typescript】通过变量的值即可获取变量的类型【typeof 变量】

注意&#xff1a;只要变量的类型准确,则typeof获取变量的类型就不会错 enum Test {a "a0",b "b0" }// 这里的a是一个变量的值 let a: Test.a "a0" as Test.a// 这里的typeof a是一个类型【Test.a】 let x: typeof a Test.a