当前位置: 首页 > news >正文

Java学习Day20:基础篇10

包装类

包装类(Wrapper Class)在编程中,特别是Java等面向对象的编程语言中,扮演着重要的角色。以下是对包装类的详细解释:

一、定义

包装类是针对基本数据类型定义的引用类型。在Java中,有八种基本数据类型(byte, short, int, long, float, double, char, boolean)和它们对应的包装类(Byte, Short, Integer, Long, Float, Double, Character, Boolean)。此外,Java还提供了BigIntegerBigDecimal类来处理超过基本数据类型范围的大数。

二、作用

  1. 方便操作基本数据类型:包装类提供了丰富的方法来操作对应的基本数据类型,如类型转换、字符串转换等。
  2. 集合操作:Java集合类(如List, Set等)只能存放引用类型的数据,不能存放基本数据类型。通过包装类,可以将基本数据类型转换为对象类型,从而放入集合中。
  3. 自动装箱与拆箱:从Java 1.5(JDK 5.0)开始,引入了自动装箱(Autoboxing)和拆箱(Unboxing)机制,使得基本数据类型和包装类之间的转换更加简便。自动装箱是指将基本数据类型自动转换为包装类对象,而拆箱则是指将包装类对象转换回基本数据类型。
  4. 数据安全性:包装类作为对象,可以通过null值来表示空,这在某些情况下比基本数据类型的默认值(如0, false等)更具表现力。

三、基本类型与包装类型的区别

  1. 存储位置:基本数据类型直接存储在堆栈中,而包装类对象则通过引用指向实例,实例保存在堆中。
  2. 初始化:基本数据类型有默认的初始值(如int默认为0),而包装类对象的初始值为null,需要显式创建实例并赋值。
  3. 功能:包装类提供了比基本数据类型更多的功能,如类型转换、字符串转换等。

四、示例

// 自动装箱
Integer num = 10; // 相当于 Integer num = Integer.valueOf(10);
// 拆箱
int i = num.intValue(); // 或者直接 int i = num; 在Java 5及以上版本
// 集合中使用包装类
List<Integer> list = new ArrayList<>();
list.add(1); // 自动装箱
int second = list.get(0); // 自动拆箱
// 字符串转换
String str = Integer.toString(num);
int numFromStr = Integer.parseInt(str);

五、注意事项

  1. 性能考虑:在性能敏感的场景下,需要注意自动装箱和拆箱可能带来的性能开销。
  2. 空指针异常:由于包装类对象可能为null,因此在使用包装类对象时需要特别注意空指针异常的问题。
  3. 缓存机制:Java对Integer等包装类实现了缓存机制,对于-128到127之间的值,会缓存其对应的包装类对象。这意味着在这个范围内的值进行装箱时,可能会返回同一个对象。但这并不意味着所有包装类都有这样的缓存机制。

综上所述,包装类在Java等面向对象的编程语言中扮演着重要的角色,它们不仅提供了对基本数据类型的封装和扩展功能,还使得基本数据类型能够更方便地参与到面向对象的编程中。

ArrayList

1.ArrayList类继承体系

ArrayList类的继承体系在Java中是非常明确的。ArrayList是Java集合框架中的一个重要类,它主要继承自AbstractList<E>类,并实现了List<E>接口、RandomAccess接口、Cloneable接口和java.io.Serializable接口。

这一继承体系使得ArrayList具备了丰富的功能和特性,包括动态数组的实现随机访问克隆能力以及序列化能力等。

具体来说,ArrayList的继承体系可以表示为:

java.lang.Object
└── java.util.AbstractCollection<E>
└── java.util.AbstractList<E>
└── java.util.ArrayList<E>

ArrayList实现接口

  • List<E>:提供了列表操作的基础接口,如添加、删除、遍历等。
  • RandomAccess:表明ArrayList支持随机访问,即可以通过索引快速访问列表中的元素。
  • Cloneable:表明ArrayList可以被克隆。
  • java.io.Serializable:表明ArrayList支持序列化,可以将对象状态保存到文件中或通过网络传输。

add底层代码解析

public void add(int index, E element) {  
    // 首先,检查索引是否有效,即是否在0到size之间(不包括size)  
    rangeCheckForAdd(index);  
  
    // 每当结构被修改时,modCount增加  
    modCount++;  
  
    final int s; // 临时变量,用于存储当前列表的大小  
    Object[] elementData; // 临时变量,用于引用elementData数组  
  
    // 如果当前列表大小等于其底层数组的大小,则需要进行扩容  
    if ((s = size) == (elementData = this.elementData).length)  
        elementData = grow(); // 调用grow方法进行扩容  
  
    // 将从index位置开始的元素向后移动一位,为新元素腾出空间  
    System.arraycopy(elementData, index,  
                     elementData, index + 1,  
                     s - index);  
  
    // 在指定位置插入新元素  
    elementData[index] = element;  
  
    // 更新列表的大小  
    size = s + 1;  
}
关键步骤解析
索引有效性检查:
通过rangeCheckForAdd(index)方法检查传入的索引值index是否有效。如果索引小于0或大于等于当前列表的大小size,则会抛出IndexOutOfBoundsException。
扩容处理:
如果当前列表的大小(size)等于底层数组elementData的长度,说明数组已经满了,无法再添加更多元素。此时,会调用grow()方法进行扩容。grow()方法通常会将数组的大小增加到原来的1.5倍(具体实现可能因JVM版本而异),然后返回新的数组。注意,这里的elementData变量在扩容后会被更新为指向新的数组。
元素移动:
使用System.arraycopy方法将索引index及之后的元素向后移动一个位置,为新元素腾出空间。System.arraycopy是一个本地方法,它提供了比手动循环复制更高的性能。
插入新元素:
在腾出的位置(即索引index处)插入新元素element。
更新列表大小:
将列表的大小size增加1,以反映新添加的元素。

sout底层代码

在Java中,当你使用System.out.println()来打印一个对象时(包括集合对象如ArrayList),输出之所以不是内存地址(即对象的引用在内存中的直接表示),是因为Java的Object类(所有类的超类)提供了一个toString()方法,该方法被设计为返回对象的字符串表示。对于ArrayList和其他许多Java集合类,toString()方法已经被重写以提供更有用的信息,即集合中元素的字符串表示。

return (obj == null) ? "null" : obj.toString();
对象自动调用tostring将object转为String型;

forEach 方法

是 JavaScript 中一个常用于数组(Array)的方法,它允许你对数组的每个元素执行一个回调函数。这个回调函数会接收三个参数:当前元素的值、当前元素的索引(可选)、以及正在被遍历的数组本身(可选)。但是,需要注意的是,forEach 方法不会改变原数组,也不会返回新的数组,它只是用来遍历数组中的每个元素。

如果在遍历过程中修改了集合(modCount变化),则抛出ConcurrentModificationException

LinkedList

1.add(E e):

在列表末尾添加指定的元素。

 add(int index, E element): 在列表的指定位置插入指定的元素。

2.get(int index):

返回列表中指定位置的元素。

3.迭代器和for each的区别

for each 循环(也称为增强型 for 循环)和迭代器(Iterator)在Java中都是用于遍历集合(如List、Set)和数组的重要工具,但它们之间存在一些关键的区别。以下是两者的主要区别:

1. 底层实现
  • for each 循环for each 循环是Java 5(JDK 1.5)引入的一种语法糖,用于简化集合和数组的遍历。其底层实际上是通过迭代器(Iterator)来实现的。因此,当你使用 for each 循环遍历集合时,Java编译器会自动为你处理迭代器的创建和遍历逻辑。
  • 迭代器(Iterator):迭代器是一个专门用于遍历集合的接口,它提供了统一的方法来遍历集合中的元素,而不需要了解集合的内部结构。迭代器接口包含hasNext()next()remove()等方法,用于检查序列中是否还有更多元素、获取序列中的下一个元素以及从迭代器遍历的集合中移除迭代器最后返回的元素。
2. 使用方式
  • for each 循环:使用简单直观,代码更简洁。它隐藏了迭代器的创建和遍历细节,使得遍历集合或数组的操作更加容易理解。
    for (ElementType element : collection) {
    // 处理元素
    }
  • 迭代器:使用迭代器需要显式地获取迭代器的实例,并调用其方法来遍历集合。这提供了更多的灵活性,但代码相对复杂一些。
    Iterator<ElementType> iterator = collection.iterator();
    while (iterator.hasNext()) {
    ElementType element = iterator.next();
    // 处理元素
    }
3. 功能差异
  • for each 循环:虽然简单易用,但在遍历过程中不能直接修改集合(如添加或删除元素),除非集合本身支持并发修改(如CopyOnWriteArrayList),否则可能会抛出ConcurrentModificationException异常。这是因为for each循环底层使用迭代器,而迭代器在遍历过程中默认不允许修改集合。
  • 迭代器:迭代器提供了remove()方法,允许在遍历过程中安全地删除元素(即迭代器最后返回的元素)。但是,尝试在调用next()方法之前或调用next()方法之后调用remove()方法将抛出IllegalStateException异常。
4. 性能考虑
  • 在大多数情况下,for each 循环和迭代器的性能差异可以忽略不计,因为它们底层都使用了类似的机制来遍历集合。然而,在某些特定情况下(如遍历LinkedList时),迭代器的性能可能会略优于for each循环,因为LinkedList的随机访问性能较差,而迭代器可以通过顺序访问来优化性能。
总结

for each 循环和迭代器都是Java中遍历集合和数组的有效工具。for each 循环以其简洁易用的特点受到广泛欢迎,而迭代器则提供了更多的灵活性和控制力。在选择使用哪种方式时,应根据具体的需求和场景来决定。

4.一些信息

LinkedList 在 Java 中是一个基于链表的数据结构,它实现了 List 接口和 Deque 接口。LinkedList 可以包含任何类型的对象,因为它是泛型的。这意味着你可以为 LinkedList 指定一个具体的类型参数,使其只能存储该类型的对象或该类型的子类型的对象。

LinkedList 的数据类型(即它可以包含的元素类型)可以是任何类(包括自定义类)的实例,或者是 Java 提供的任何基本数据类型的包装类(如 IntegerDoubleCharacter 等,对应于基本类型 intdoublechar 等)。

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 二进制与进制转换与原码、反码、补码详解--内含许多超详细图片讲解!!!
  • React(四):DOCX文件在线预览
  • 2024杭电多校(5) 1008. 猫咪们狂欢【带权最大独立集】
  • 宅家也能高效办公?试试这四款款远程控制神器!
  • 【2024年华数杯全国大学生数学建模竞赛】C题:老外游中国 问题思路分析及Python代码实现
  • C语言初阶(12)
  • 周鸿祎回应将成三六零第一大股东:会和公司一起走下去
  • 学习硬件测试04:触摸按键+PWM 驱动蜂鸣器+数码管(P62~P67、P71、P72)
  • mysql介绍
  • 1、.Net UI框架:WPF - .Net宣传系列文章
  • 反转链表(LeetCode)
  • 重燃代码之光:在PyCharm中恢复自动高亮的秘籍
  • Linux系统中的高级内核模块调试技术
  • override的作用和好处
  • Yarn:一个快速、可靠且安全的JavaScript包管理工具
  • 【EOS】Cleos基础
  • 【译】理解JavaScript:new 关键字
  • centos安装java运行环境jdk+tomcat
  • github从入门到放弃(1)
  • java取消线程实例
  • LeetCode刷题——29. Divide Two Integers(Part 1靠自己)
  • PAT A1050
  • React 快速上手 - 06 容器组件、展示组件、操作组件
  • 百度贴吧爬虫node+vue baidu_tieba_crawler
  • 第三十一到第三十三天:我是精明的小卖家(一)
  • 跨域
  • 前端性能优化——回流与重绘
  • 深度学习入门:10门免费线上课程推荐
  • 推荐一个React的管理后台框架
  • Java性能优化之JVM GC(垃圾回收机制)
  • 翻译 | The Principles of OOD 面向对象设计原则
  • 说说我为什么看好Spring Cloud Alibaba
  • 完善智慧办公建设,小熊U租获京东数千万元A+轮融资 ...
  • 正则表达式-基础知识Review
  • ​低代码平台的核心价值与优势
  • ## 临床数据 两两比较 加显著性boxplot加显著性
  • ###项目技术发展史
  • #HarmonyOS:软件安装window和mac预览Hello World
  • (1)(1.13) SiK无线电高级配置(五)
  • (14)目标检测_SSD训练代码基于pytorch搭建代码
  • (2/2) 为了理解 UWP 的启动流程,我从零开始创建了一个 UWP 程序
  • (6)【Python/机器学习/深度学习】Machine-Learning模型与算法应用—使用Adaboost建模及工作环境下的数据分析整理
  • (C#)Windows Shell 外壳编程系列9 - QueryInfo 扩展提示
  • (C语言)字符分类函数
  • (笔记)Kotlin——Android封装ViewBinding之二 优化
  • (二)PySpark3:SparkSQL编程
  • (附源码)ssm旅游企业财务管理系统 毕业设计 102100
  • (离散数学)逻辑连接词
  • (生成器)yield与(迭代器)generator
  • (十八)devops持续集成开发——使用docker安装部署jenkins流水线服务
  • (限时免费)震惊!流落人间的haproxy宝典被找到了!一切玄妙尽在此处!
  • (一)Kafka 安全之使用 SASL 进行身份验证 —— JAAS 配置、SASL 配置
  • (原创)可支持最大高度的NestedScrollView
  • (转)四层和七层负载均衡的区别
  • ***通过什么方式***网吧