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

Day8 trim方法String的偏底层字符串常量池intern方法装箱拆箱集合的ArrayList,LinkedListStringBuilder/Buffer

感觉自己学的有点多了,前面的知识没太复习,写代码的时候都得回头看看一些方法是谁的。我的妈呀。还是得多回头看。

先复盘吧

trim方法

String字符串的方法

删去字符串前后位置中的空白位。

什么是空白位:空格,\n,\r,\f,\t这些都是空白位

//trim() //去除字符串前后位置的空白位 \r 回车 \n 换行 \t 制表符 \f 换页都算空白位 str = "\r \n a b c \t \f"; //\r 回车 \n 换行 \t System.out.println(str); System.out.println("-------------"); String result = str.trim(); System.out.println(result);

这个运行结果输出就是a b c

再复习复习String字符串的其他方法

split indexOf/LastIndexOf CharAt replace/replaceAll length substring toCharArray equals

String的偏底层

String的类定义中

他的字符串的真实值其实是用final修饰的,即String实例化出的对象内容不可以改变(String对象是不可变对象、不可变量),那么String的引用修改内部内容时是如何作用的?

其实是生成了一个新的String对象,然后引用再指向这个新的对象。

另一个问题就出现了,你要是这样的话是不是就会产生大量的内存空间浪费,也可能导致内存溢出(OOM),所以为了解决这个问题就整出来了个字符串缓冲池和可变字符串StringBuilder和StringBuffer。

字符串常量池

常量池在堆中

存储通过值来声明的字符串String对象

目的:

为了能够达到减少内存消耗,对象重用的效果,Java中提供了字符串常量池,减少字符串定义的消耗

工作原理:

当Java程序需要定义(创建)一个字符串,不会直接开辟空间,而是先到字符串常量池中查阅查看是否有对应的字符串内容(副本),如果有,则直接使用字符串常量池中的对象。如果没有的话,在常量池创建一个副本,然后再使用此副本

注:不是任何创建或定义字符串的方法都会存入缓冲池,只有使用值的方式声明的字符串才会进入常量池,即让"1234"作为一个String字符串对象进入常量池

具体代码

String a = "1234"; String a1 = "1234";

1234就是一个String对象,通过值的方式声明,存储在缓冲池,如果其他String引用也通过值这种方式声明,如a1,也会将缓冲池中的"1234"String对象地址给a1,所以a==a1是成立的。

而如果是new的会先去常量池查找有没有这个String对象,如果有,就会在堆中开辟一个新的空间,将常量池中的String对象的值赋给新实例化的对象,并将这个新的对象的地址给引用。如果常量池中没有,就会在常量池中先实例化这个对象,new出来的String对象的值会指向常量池中这个对象的值,下面是代码解释

//并不是所有的字符串都会加入字符串常量池 //只要是new都是一个新的独立的内容 String s1 = "1234"; String s2 = "1234"; String s3 = new String("1234"); //1234是作为值来参与new String的初始化函数的,他会先去常量池去找有没有1234这个对象,如果有就创建一个新的对象 // 这个对象全部指向常量池中的对象的值,如果常量池中没有,那就先在常量池中先创建这个对象,然后在堆中 //声明的对象会指向常量池中的对象的值 new String("1234"); //这个语句执行会创建一个或两个对象

所以,new String("1234");可能会创建一个或两个对象

StringBuilder/Buffer

字符串拼接时,或使用+拼接时,每次拼接都会产生一个新的字符串 ,当需要连续多次拼接时,会产生大量的中间串,会消耗大量内存 ,为了避免产生中间串,java提供了可变字符串类型,可变长度,不是final private了

这是优化内存空间的另一个方法,这两个是可变字符串数组类,其中的值不是用final修饰的,可以对原有的字符串数组进行扩展和延申,不过扩展延申也是重新开辟了一个空间,只是old和新的开辟的空间大小不同。

他们默认开辟的空间大小为16,后面扩容每次扩为原来的二倍。

这两个是可变数组,但是也是可以转为正常数组的。

String result = ""; for(int i = 0;i<100;i++){ result = result+i; } System.out.println(result); //字符串拼接时,或使用+拼接时,每次拼接都会产生一个新的字符串 //当需要连续多次拼接时,会产生大量的中间串,会消耗大量内存 //为了避免产生中间串,java提供了可变字符串类型,可变长度,不是final private了 //StringBuilder StringBuffer StringBuilder stringBuilder = new StringBuilder(); stringBuilder = new StringBuilder(20);//修改容量 stringBuilder = new StringBuilder('a');//将a当作一个容量去存储的,a前面是capacity,容量为a的ACII编码值 stringBuilder = new StringBuilder("123");//将123这个字符串放里面,不是声明容量,和声明容量方法不同 for(int i = 0;i<100;i++){ stringBuilder.append(i); } //StringBuilder 和StringBuffer都是可变字符串, /// 为什么会有两个,一个是线程安全 Builder安全,一个是线程不安全 //内部提供了一个可变化的value数组 //默认初始容量为16,,每次扩容扩两倍 result = stringBuilder.toString(); System.out.println(result); System.out.println(stringBuilder.length()); //这个就不会产生中间字符串对象,因为他是可变字符数组

String的常量编译优化问题以及值String对象和newString对象的拼接

String s1 = "1234"; String s2 = "1234"; String s3 = new String("1234"); //1234是作为值来参与new String的初始化函数的,他会先去常量池去找有没有1234这个对象,如果有就创建一个新的对象 // 这个对象全部指向常量池中的对象的值,如果常量池中没有,那就先在常量池中先创建这个对象,然后在堆中 //声明的对象会指向常量池中的对象的值 new String("1234"); //这个语句执行会创建一个或两个对象 String s4 = new String("1234"); String s5 ="12"+"34";//编译代码时已经将12 34拼接完成,运行代码时,就是s5="1234" String s6 ="1"+"2"+"3"+"4"; String s7 ="12"+new String("34");//字符串只要不是编译时就能确定的结果(需要在运行时拼接) // 那就会创建一个新的对象,让引用指向他 String s7a ="12"+new String("34"); String s8a ="12"; String s8b ="34"; String s8 = s8a+s8b; String s9 = s8a+s8b; ///常量编译优化----------得了解 System.out.println(s1==s5);//T/F ------true System.out.println(s1==s2);//true System.out.println(s1==s3);//false System.out.println(s3==s4);//false System.out.println(s1==s6);//常量编译优化true System.out.println(s5==s6);//常量编译优化true System.out.println(s1==s7);//false, System.out.println(s3==s7);//false System.out.println(s7==s7a);//false System.out.println(s1==s8);//false System.out.println(s8==s9);//false

只要是值操作,在编译的时候就可以确定拼接后的结果。如果有String开辟新空间或者引用拼接,那就会创建一个新对象,让引用指向他

intern方法

并不是所有字符串都会加入常量池

String str = new String(new char[]{'1','2','3'});

这个就不会在常量池生成对象。那么如何让他进入常量池,即使用intern方法

intern的使用方法:

String str = new String(new char[]{'1','2','3'}); String str1 = str.intern();

intern方法的作用过程:先去常量池寻找有没有这个String对象,如果有,则返回这个对象的地址,如果没有,则在常量池创建对象,并返回地址

注:当两个字符串的equals比较为true,两个字符串的inter方法==比较一定为true

装箱&拆箱

Java是一个面向对象的语言,但是也有非对象的数据类型,比如基本数据类型

为了圆这个坑,就创建了基本数据类型类,即封装类,基本数据类型和封装类间可以转换

//byte short int long char float double boolean //封装类型Byte Short Integer Long Character Float Double Boolean //整数和浮点数类型的封装类都是继承自Number,超级父类是Number

所有的封装类都有一个超级父类,Number类

装箱:基本数据类型转为对应的封装类

拆箱:封装类转为对应的基本数据类型

//基本数据类型和对应的封装类型可以相互转换 byte b = 12; Byte b1 = 12; b =new Byte("12");//JDK9后就废弃了这个方法,但是不影响 b = Byte.valueOf("12"); //基本数据类型转为对应封装类型叫做装箱 //基本数据类型的封装类型转为基本数据类型这个过程叫做拆箱 Integer a = 12;//装箱 int c = new Integer(12);//拆箱

封装类型的缓存

机理类似于常量池,封装类型也有自己的常用池,整数类型的封装类型,有缓存,但不是所有的数都有缓存,范围是从-128~127,且Integer封装类型的缓存可以通过修改JVM的参数来修改缓存大小,boolean也有缓存,因为就true和fales。

Integer i1 = 12; Integer i2 = new Integer(12); // Integer i2 = Integer.valueOf("15"); System.out.println(i1==i2);//false Integer i3 = 12; System.out.println(i1==i3);//true Integer i4 = -128; Integer i5 = -128; System.out.println(i4==i5);//true i4 = 128; i5 = 128; System.out.println(i4==i5);//false Character c1 = 'a'; Character c2 = 'a'; System.out.println(c1==c2);//true int numa = 1000; Integer numb=1000; //基本数据类型和引用装箱类型==比较,将引用类型拆箱后再比较,和缓存就没有关系了 System.out.println(numa==numb);//true

超出了缓存范围就会创建一个对应类型的对象。

ArrayList&LinkedList

这个先从实现类说起,慢慢说到集合

集合(Collection)

集合是一个接口

有三类容器,List Set Map

其中List Set Map

List下有三个实现类:ArrayList LinkedList Vector

List和Set有一个共同的父接口Collection

ArrayList

ArrayList,顾名思义,数组链表,通过动态数组保存数据,使用数组实现链接

private static final int DEFAULT_CAPACITY = 10; private static final Object[] EMPTY_ELEMENTDATA = {}; private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}; transient Object[] elementData; // non-private to simplify nested class access private int size;

查看ArrayList的源码,发现他的elementData;并不是final修饰,size也不是final修饰,这就说明他是一个可变动态数组,且初始默认大小是10。

每个节点可以存储任何类型的对象

初始大小为10,每次扩容变为原来的1.5倍

每个下标都是一个对象,对象可以是任意类型,他们的超父类是Object类

所有的List都是有序集合,存入是什么顺序就是什么顺序了(后面有无序的

然后再说一下ArrayList中的方法:

1>list1引用名.add()

向链表中加入一个数据对象,如果是基本数据类型则会进行自动的装箱操作,然后保存对应的封装对象。也可以向其中存null值(有不可以存null值的,因为后面有的容器需要比较hash值进行无序存储,比如TreeSet,大部分的Map)

2>list1.set(下标位置,对象或值)

3>list1.remove(下标位置)

4>list1.get(下标位置)//返回下标中的对象

5>list1.size()返回数组大小

LinkedList

LinkedList使用链表实现的,还是用双向链表实现的,每个链表都是由结点构成,方法和ArrayList实现方法相同,但是底层实现方式不相同。所以ArrayList和LinkedList在功能上的性能会有差距。

ArrayList查找快,增删慢

LinkedList查找慢,增删快

因为ArrayList可以通过下标定位数组位置,直接找到对应对象,所以查找快,但是增删的话需要将后面的所有对象都移动,所以增删慢。

而LinkedList查找需要从头节点或者尾结点开始遍历查找,所以查找慢,但是删除的话只需要改变他们的fore指针和next指针就可以实现结点的删除或增加,所以增删快。

为什么要用双向链表?

因为这样检索的效率会提升。可以从两个方向查找数据,依据下标所在位置,分别从前或后找到对应位置,加快检索效率,他查找数据可以从两个方向查找。

注:

List可以存储重复的值以及null值。

List的遍历:

使用foreach方法

for(Object obj:list){

代码块

}

http://www.cnnetsun.cn/news/1952085.html

相关文章:

  • 避坑!这些毕设太好抄了,3000+毕设案例推荐第1071期
  • 细胞造万物:当生物制造成为“十五五”新风口,我们如何抓住30万亿美元的未来?
  • 【Agent】智能体基础入门(技术发展路线+TAO循环+function calling)
  • 豆包 LeetCode 1444.切披萨的方案数 public int ways(String[] pizza, int k)
  • HCIP学习19 BGP 跨自治系统互通综合实验
  • RabbitMQ实战:极端场景下消息零丢失全攻略——生产级完整方案
  • 别再只盯着零偏了!IMU选型中那些被忽视的‘隐形杀手’:振动敏感度与温度漂移实战分析
  • 机器学习模型泛化难题:从欠拟合到过拟合的实战诊断与调优
  • 从NS方程到润滑膜压力:雷诺方程推导与有限差分法求解实践
  • Playwright登录态复用:从Pytest Fixture到Page Object模式的工程实践
  • 深入WebRTC音频处理内核:从频谱平坦度到维纳滤波,一次搞懂ns_core.c的降噪逻辑
  • 从PWM到模拟信号:低通滤波器设计的工程实践与参数权衡
  • 不只是仿真:挖掘Icarus Verilog (iverilog) 的隐藏技能,比如把Verilog代码转成VHDL
  • W800开发板到手别慌,3天搞定开发环境与固件下载(保姆级避坑指南)
  • 低代码平台,开启企业数字化创新新时代!
  • 手把手教你:神州数码DCN无线AP从开箱到上线(附静态IP配置与AC二层发现避坑指南)
  • 避坑指南:Amos路径分析输出结果里,这5个常被忽略的参数(如Condition Number, M.I.)才是模型好坏的‘隐藏裁判’
  • 收藏备用|Java程序员转型大模型开发全指南(小白/资深开发者通用)
  • 火速报名 | 2026中国高校计算机大赛——大数据挑战赛,五星级巅峰对决,邀您问鼎!
  • OBS多平台直播终极指南:免费插件完整使用教程
  • 从零到一:前端集成腾讯云IM SDK构建实时会话功能
  • MATLAB调用C++ DLL实战:手把手教你用VS2017生成并集成到Simulink模型(附MinGW-w64安装避坑)
  • 保姆级教程:用Arduino IDE给ESP32安装开发环境,避开国内网络下载坑
  • 深入STM32F429的‘网络心脏’:图解MAC与PHY如何协同工作(附MII/RMII接口详解)
  • 3D 地球卫星轨道可视化平台开发 Day1(3D 场景、卫星渲染与筛选交互实现)
  • 阿里立下五年1000亿美元云和AI商业化目标,“HappyHorse”能助力阿里云打赢硬仗吗?
  • 深度剖析:LangGraph中的状态管理与循环逻辑
  • 自然语言即代码?SITS2026实测TOP3模型准确率骤降47%:从Prompt工程到编译验证的全链路调优手册
  • 技能(skill)与智能体(agent):AI时代的专业分工
  • PHP SAAS 框架常见问题——配置问题——腾讯地图配置