Java的包装类与String类详解(底层与内存)
封装类
封装类简介
定义
Java的数据类型分为基本数据类型和引用数据类型, 但是Java也为基本数据类型分别设计了对应的类
这就是包装类(Wrapper Classes)
8个包装类
其中除了Boolean和Character之外, 其他的六种包装类都继承自类Number
封装类性质
包装类初始化
手动拆箱装箱
- JDK5之前, Java采取的是手动拆箱和装箱方法
手动装箱
public static void main(String[] args) {
int n1 = 100;
Integer integer = new Integer(n1);
Integer integer1 = Integer.valueOf(n1);
}
手动拆箱
int i = integer1.intValue();
自动拆箱装箱
- 但是JDK5之后, Java实现了自动装箱方法, 本质没有发生变化, 底层还是使用的valueOf()以及intValue()
自动装箱
int n2 = 100;
Integer integer2 = n2;
自动拆箱
int n3 = integer2;
包装类方法
1. 包装类转string
方式一
String str = integer1 + "";
方式二
String str2 = integer1.toString();
方式三
String str3 = String.valueOf(integer1);
2. String转包装类
方式一
String str = "12345";
Integer i1 = Integer.parseInt(str); // 自动装箱
方式二
Integer i1 = new Integer(str);
其他常用方法
- Integer的最大值和最小值, 其他包装类同理
Integer.MAX_VALUE
Integer.MIN_VALUE
- Character的
isXXX()
方法, 可以判断是否是xxx
String
String剖析
结构剖析
-
使用Unicode编码, 一个字符(字母或者汉字)占用两个字节
-
实现Serializable接口, 可以串行化: 可以网络传输
-
实现了comparable接口 可以比较
-
实现了很多构造器
-
String是final类, 不能被其他类继承
-
String有属性 private final char value[], 用于存在字符串内容, 不可修改, 但是不代表字符不可修改
代表的是地址无法修改
创建剖析
方式一: 直接赋值
String str = "AAA";
解释:
先从常量池查看有无"AAA", 如果有, 直接指向, 如果没有则重新创建, 然后指向
所以最终指向的是常量池的地址
方式二: 使用构造器
String str = new String("AAA");
解释
先在堆中创建空间, 里面维护了value属性, 指向常量池的"AAA"空间, 从常量池查看有无"AAA", 如果有, 直接令value指向, 如果没有则重新创建, 然后指向
所以最终指向的是堆中的地址
String对象特性
- 字符串是不可变的, 如果改变字符串, 其实会创建一个新的常量对象
String s1 = "AA";
s1 = "BB";
这里常量池会出现两个对象, 一个"AA", 一个"BB"
String str = "Hello" + "ABC";
这里不是创建三个对象, 只会创建一个对象, 因为编译器会优化, 等价于String str = "HelloABC"
String a = "AA";
String b = "BB";
String c = a + b;
前两句创建了两个常量池对象, 但是后面有所不一样
- 首先创建了StringBuilder对象
- 其次执行append方法, 将"AA" append进去
- 将"BB" append进去
- 返回的是StringBuilder的toString()方法
综上分析, 最后其实是让c指向堆中的对象, 然后这个对象的value数组指向常量池的"AABB"
所以a, b是常量池对象, c是堆对象
总结: 常量相加, 在常量池, 变量相加, 在堆
String常用方法
equals()
区分大小写判断是否相等equalsIgnoreCase
不区分大小写判断是否相等length()
获取字符个数indexOf
获取字符在字符串中第一次出现的索引, (也可以传入字符串)lastIndexOf
获取字符在字符串中最后一次出现的索引substring
截取指定范围字符串trim
去前后空格charAt
获取某索引处的字符, 因为String不能利用[]索引
...
PS: 有个印象, 到时候现查现用即可
StringBuffer
代表可变的字符序列, 可以对字符内容进行增删, 很多方法与String相同
结构剖析
- StringBuffer的直接父类是AbstractStringBuilder
- 实现了Serializable, 可以串行化
- 在父类中, 存在char[] value, 注意不是final, 所以存放在堆中
- StringBuffer是一个final类, 不可以被继承
结论: StringBuffer保存的是字符串变量, String保存的是字符串常量, 所以更改
StringBuffer的话可以直接更新内容, 不需要更改地址, 效率较高
StringBuffer转换与初始化
1.构造器
StringBuffer stringBuffer = new StringBuffer();
创建一个大小为16的char数组, 用来存放字符内容
StringBuffer stringBuffer = new StringBuffer(100);
可以直接指定char数组的容量
StringBuffer stringBuffer = new StringBuffer("hello");
当传入一个string时, 其实创建的char数组大小为string.length + 16, 然后再将string拼接进去
- String和StringBuffer之间的转化
String -> StringBuffer
1). 利用构造器(上述
2). 利用append
可以将String加到StringBuffer后面
StringBuffer -> String
1). 利用StringBUffer的toString方法
2). 使用构造器
String s = new String(stringBuffer);
StringBuffer方法
append(str)
, 可以在buffer后面追加string, (传入int等也可以自动转成string)delete(l, r)
删除[l, r) 的字符replace(l, r, str)
使用str替换[l, r) 的字符indexOf(str)
查找指定字串在字符串中第一次出现的索引insert(x, str)
在索引为x的位置前面插入strlength()
返回长度
...
StringBuilder
一个可变的字符序列, 提供了与StringBuffer兼容的API, 但是不保证同步(不是线程安全的)
该类呗设计用作StringBuffer的一个简易替换, 用在字符串缓冲区被单个线程使用的时候
如果可能, 建议优先采用该类, 因为在大多数实现中, 它比StringBuffer快
剖析
- 同样继承了AbstractStringBuilder
- 实现了Serializable, 可以串行化
- 同样是个final类, 不可以被继承
- 数据仍然存储在char[] value中, 所以仍然在堆中
- 不是线程安全的
StringBuffer, String, StringBuilder总结
-
如果字符串存在大量修改, 一般使用StringBuilder或者StringBuffer
同时如果单线程, 使用String Builder, 否则使用StringBuffer -
如果字符串很少修改, 被多个对象引用, 比如配置信息, 可以使用String
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)