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

二十九、String的不可变性

一、String的基本特性

1.String:字符串,使用一对“”引起来表示
1)String s1 = “hallo”; //字面量的定义方式
2)String 说 = new String(“hello”)’
2.String声明为final的,不可被继承。
3.String实现了Serialzable接口:表示字符串是支持序列化的。实现了Comparable接口:表示String可以比较大小。
4.String在jdk8及以前内部定义了final char[] vaule用于存储字符串数据。jdk9时改为bytr[]。
5.String:代表不可变的字符序列。简称:不可变性。
1)当对字符串重新赋值时,需要重写指定内存区域赋值,不能使用原有的value进行赋值。
2)当对现有的字符串进行链接操作时,也需要重新指定内存区域赋值,不能使用原有的value进行赋值。
3)当调用String的replace()方法修改指定字符或字符串时,也需要重新指定内存区域赋值,不能使用原有的value进行赋值。
6.通过字面量的方式(区别于new)给一个字符串赋值,此时的字符串值声明在字符串常量池中。
字符串常量池中是不会存储相同内容的字符串的。

String底层Hashtable结构的说明
7.String的String Pool是一个固定大小的Hashtable,默认值大小长度是1009。如果放进String Pool的String非常多,就会造成Hash冲突严重,从而导致链表会很长,而链表长了后直接回造成的影响就是当调用String.intern时性能会大幅下降。
8.使用-XX:StringTableSize可设置StringTable的长度。
9.在JDK6中SringTable是固定的,就是1009的长度,所以如果常量池中的字符串过多就会导致效率下降很快。StringTableSize设置没有要求。
10.在jdk7中,StrngTable的长度默认值是60013,1009是可设置的最小值。

二、String的内存分配

1.在Java语言中有8种基本数据类型和一种比较特殊的类型String。这些类型为了使它们在运行过程中速度更快、更节省内存,都提供了一种常量池的概念。
2.常量池就类似一个Java系统级别提高的缓存。8种基本数据类型的常量池是系统协调的,String类型的常量池比较特殊。它的主要使用方法有两种。
1.直接使用双引号声明出来的String对象会直接存储在常量池中。
比如:String info = “atguigu.com”;
2.如果不是用双引号声明的String对象,可以使用String提供的intern()方法。这个后面重点谈。
3.Java6及以前,字符串常量池存放在永久代。
4.Java7种Oracle的工程师对字符串池的逻辑做了很大的改变,即将字符串常量池的位置调整到Java堆。
1)所有的字符串都保存在堆种,和其他普通对象一样,这样可以让你在进行调优应用时仅需调整大小就可以了。
2)字符串常量池概念原本使用得比较多但是这个改动使得我们有足够的理由让我们重新考虑在Java7中使用Strig.intern().
5.Java8元空间,字符串常量在堆

三、字符串拼接操作

1.常量与常量的拼接结果在常量池,原理是编译器优化。
2.常量池中不会存在相同内容的常量。
3.只要其中有一个是变量,结果就在堆中。变量拼接的原理是StringBuilder。
4.如果拼接的结果调用它intern()方法,则主动将常量池中还没有的字符串对象放入池中,并返回此对象地址。

import org.junit.Test;/*** 字符串拼接操作* @author */
public class StringTest5 {@Testpublic void test1(){String s1 = "a" + "b" + "c";//编译期优化:等同于"abc" String s2 = "abc"; //"abc"一定是放在字符串常量池中,将此地址赋给s2/** 最终.java编译成.class,再执行.class* String s1 = "abc";* String s2 = "abc"*/System.out.println(s1 == s2); //trueSystem.out.println(s1.equals(s2)); //true}@Testpublic void test2(){String s1 = "javaEE";String s2 = "hadoop";String s3 = "javaEEhadoop";String s4 = "javaEE" + "hadoop";//编译期优化//如果拼接符号的前后出现了变量,则相当于在堆空间中new String(),具体的内容为拼接的结果:javaEEhadoopString s5 = s1 + "hadoop";String s6 = "javaEE" + s2;String s7 = s1 + s2;System.out.println(s3 == s4);//trueSystem.out.println(s3 == s5);//falseSystem.out.println(s3 == s6);//falseSystem.out.println(s3 == s7);//falseSystem.out.println(s5 == s6);//falseSystem.out.println(s5 == s7);//falseSystem.out.println(s6 == s7);//false//intern():判断字符串常量池中是否存在javaEEhadoop值,如果存在,则返回常量池中javaEEhadoop的地址;//如果字符串常量池中不存在javaEEhadoop,则在常量池中加载一份javaEEhadoop,并返回次对象的地址。String s8 = s6.intern();System.out.println(s3 == s8);//true}@Testpublic void test3(){String s1 = "a";String s2 = "b";String s3 = "ab";/*如下的s1 + s2 的执行细节:(变量s是我临时定义的)① StringBuilder s = new StringBuilder();② s.append("a")③ s.append("b")④ s.toString()  --> 约等于 new String("ab")补充:在jdk5.0之后使用的是StringBuilder,在jdk5.0之前使用的是StringBuffer*/String s4 = s1 + s2;//System.out.println(s3 == s4);//false}/*1. 字符串拼接操作不一定使用的是StringBuilder!如果拼接符号左右两边都是字符串常量或常量引用,则仍然使用编译期优化,即非StringBuilder的方式。2. 针对于final修饰类、方法、基本数据类型、引用数据类型的量的结构时,能使用上final的时候建议使用上。*/@Testpublic void test4(){final String s1 = "a";final String s2 = "b";String s3 = "ab";String s4 = s1 + s2;System.out.println(s3 == s4);//true}//练习:@Testpublic void test5(){String s1 = "javaEEhadoop";String s2 = "javaEE";String s3 = s2 + "hadoop";System.out.println(s1 == s3);//falsefinal String s4 = "javaEE";//s4:常量String s5 = s4 + "hadoop";System.out.println(s1 == s5);//true}/*体会执行效率:通过StringBuilder的append()的方式添加字符串的效率要远高于使用String的字符串拼接方式!详情:① StringBuilder的append()的方式:自始至终中只创建过一个StringBuilder的对象使用String的字符串拼接方式:创建过多个StringBuilder和String的对象② 使用String的字符串拼接方式:内存中由于创建了较多的StringBuilder和String的对象,内存占用更大;如果进行GC,需要花费额外的时间。改进的空间:在实际开发中,如果基本确定要前前后后添加的字符串长度不高于某个限定值highLevel的情况下,建议使用构造器实例化:StringBuilder s = new StringBuilder(highLevel);//new char[highLevel]*/@Testpublic void test6(){long start = System.currentTimeMillis();//        method1(100000);//4014method2(100000);//7long end = System.currentTimeMillis();System.out.println("花费的时间为:" + (end - start));}public void method1(int highLevel){String src = "";for(int i = 0;i < highLevel;i++){src = src + "a";//每次循环都会创建一个StringBuilder、String}
//        System.out.println(src);}public void method2(int highLevel){//只需要创建一个StringBuilderStringBuilder src = new StringBuilder();for (int i = 0; i < highLevel; i++) {src.append("a");}
//        System.out.println(src);}
}

字符串变量拼接操作的底层原理
在这里插入图片描述
拼接操作与append操作的效率对比
通过StringBuilder的append()的方式添加字符串的效率要远高于使用String的字符串拼接方式!
详情:1.StringBuilder的append()方式:自始自终只创建一个StringBuilder的对象。使用String的字符串拼劲方式:创建过多个StringBuilder的的对象。
2.使用String的字符串拼接方式:内存中由于创建了较多的StringBuilder和String的对象,内存占用更大,如果GC,需要花费额外的时间。

四、intern的使用

1.如果不是用双引号声明的String对象,可以使用String提供的intern方法:intern方法会从字符串常量池中查询当前字符串是否存在,若不存在就会将当前字符串放入常量池中。
1)比如:Stirng myInfo = new String(“I love III”)
也就是说,如果在任意字符串上调用String.intern方法,那么其返回结果所指向的那个类实例,必须和直接以常量形式出现的字符串完全相同。因此,下列表达式的值必定是true:
(“a”+“b”+“c”).intern == ”abc“
通俗点讲,Interned String 就是确保字符串在内存李只有一份拷贝,这样可以节约内存空间,加快字符串操作任务的执行速度,注意,这个值会被存放在字符串内部池(String Intern Pool)

new String(”ab“)创建了几个对象?
一个对象是:new关键字在对空间的
另一个对象四是:字符串常量池中的对象。字节码指令:ldc

import org.junit.Test;/*** 如何保证变量s指向的是字符串常量池中的数据呢?* 有两种方式:* 方式一: String s = "shkstart";//字面量定义的方式* 方式二: 调用intern()*         String s = new String("shkstart").intern();*         String s = new StringBuilder("shkstart").toString().intern();** @author* @create*/
public class StringIntern {public static void main(String[] args) {String s = new String("1");s.intern();//调用此方法之前,字符串常量池中已经存在了"1"String s2 = "1";System.out.println(s == s2);//jdk6:false   jdk7/8:falseString s3 = new String("1") + new String("1");//s3变量记录的地址为:new String("11")//执行完上一行代码以后,字符串常量池中,是否存在"11"呢?答案:不存在!!s3.intern();//在字符串常量池中生成"11"。如何理解:jdk6:创建了一个新的对象"11",也就有新的地址。//         jdk7:此时常量中并没有创建"11",而是创建一个指向堆空间中new String("11")的地址String s4 = "11";//s4变量记录的地址:使用的是上一行代码代码执行时,在常量池中生成的"11"的地址System.out.println(s3 == s4);//jdk6:false  jdk7/8:true}}

在这里插入图片描述

/*** @author * @create */
public class StringIntern1 {public static void main(String[] args) {//StringIntern.java中练习的拓展:String s3 = new String("1") + new String("1");//new String("11")//执行完上一行代码以后,字符串常量池中,是否存在"11"呢?答案:不存在!!String s4 = "11";//在字符串常量池中生成对象"11"String s5 = s3.intern();System.out.println(s3 == s4);//falseSystem.out.println(s5 == s4);//true}
}

G1的String去重操作
1.背景:对许多Java应用(有大的也有小的)做的测试得出以下结果:
1)堆存活数据集合里面String对象占了25%。
2)堆存活数据集合里面重复的String对象有13.5%。
3)String对象的平均长度45.
2.许多大规模的Java应用的瓶颈在于内存,测试表明,在这些类型的应用里面,Java堆中存活的数据集合差不多25%是String对象。更进一步,这里面差不多一半String对象是重复的,重复的意思是说:
String1.equals(String) =true。堆上存在重复的String对象必然是一种存在的浪费。这个项目将在G1垃圾收集器中实现自动持续对重复String对象进行去重,这样就能避免浪费内存。
去重实现:
1.当垃圾收集器工作的时候,会访问堆上存活的对象。对每一个访问的对象都会检查是否候选去重的String对象。
2.如果是,把这个对象的一个引用插入到队列中等待后续的处理。一个去重的线程在后台运行,处理这个队列。处理队列的一个元素意味着从队列删除这个元素,然后尝试去重它引用的String对象。
3.使用一个hashtable来记录所有的被String对象使用的不重复char数组。当去重的时候,会查这个hashtable,来看堆上是否已经存在一个一模一样的char数组。
4.如果存在,String对象会被调整引用那个数组,释放原来的数组的引用,最终会被垃圾收集器回收掉。
5.如果查找失败,char数组会被插入到hashtable,这样以后的时候就可以共享这个数组。

相关文章:

二十九、String的不可变性

一、String的基本特性 1.String:字符串&#xff0c;使用一对“”引起来表示 1)String s1 “hallo”; //字面量的定义方式 2)String 说 new String(“hello”)’ 2.String声明为final的&#xff0c;不可被继承。 3.String实现了Serialzable接口:表示字符串是支持序列化的。实…...

TCP服务器如何使用select处理多客户连接

TCP是一种面向连接的通信方式,一个TCP服务器难免会遇到同时处理多个用户的连接请求的问题,本文用一个简化的实例说明如何在一个TCP服务器程序中,使用select处理同时出现的多个客户连接,文章给出了程序源代码,本文假定读者已经具备了基本的socket编程知识,熟悉基本的服务器…...

python字符编码

目录 ❤ 前言 文本编辑器存取文件的原理&#xff08;nodepad&#xff0c;pycharm&#xff0c;word&#xff09; python解释器执行py文件的原理 &#xff0c;例如python test.py 总结 ❤ 什么是字符编码? ASCII MBCS Unicode ❤ 字符编码的发展史 阶段一: 现代计算…...

面向对象练习题(8)

目录 第一题 第二题 第三题 第一题 思路分析&#xff1a; 1.Person p new Student();这就是一个向上转型&#xff0c;让父类的引用指向子类的对象&#xff0c;但是向上转型不能访问子类的属性和方法 我们在写代码时看的是编译类型 在运行是看的是运行类型 p.run(); p.eat(); …...

重构类关系-Extract Interface提炼接口八

重构类关系-Extract Interface提炼接口八 1.提炼接口 1.1.使用场景 若干客户使用类接口中的同一子集&#xff0c;或者两个类的接口有部分相同。将相同的子集提炼到一个独立接口中。 类之间彼此互用的方式有若干种。“使用一个类”通常意味用到该类的所有责任区。另一种情况…...

vivo手机各系列简介和拆解

Vivo是中国智能手机制造商&#xff0c;其产品线较多&#xff0c;主要包括以下系列&#xff1a; X系列&#xff1a;X系列是Vivo的高端智能手机系列&#xff0c;注重出色的拍照性能、高质量的音效和高端的设计。该系列主要面向追求高质量拍照和高端体验的用户。 V系列&#xff1…...

Redis:redis通用命令;redis常见数据结构;redis客户端;redis的序列化

一、redis命令 1.redis通用命令 Redis 通用命令是一些 Redis 下可以作用在常用数据结构上的常用命令和一些基础的命令 常见的命令有&#xff1a; keys 查看符合模板的所有key&#xff0c;不建议在生产环境设备上使用&#xff0c;因为keys会模式匹配所有符合条件的key&#…...

Java新特性

switch Java中switch的三种用法方式 JAVA中的switch Java switch 中如何使用枚举&#xff1f; 注解 天天用注解你真的知道怎么用吗&#xff1f;Java中的注解及其实现原理。 JAVA注解 JAVA注解 基础 集合判空 求和 Java8之List求和 JAVA中对list使用stream对某个字段求和…...

Java_Spring:8. Spring 中 AOP 的细节

目录 1 说明 2 AOP 相关术语 3 学习 spring 中的 AOP 要明确的事 4 关于代理的选择 1 说明 spring 的 aop通过配置的方式&#xff0c;实现上一章节的功能。 2 AOP 相关术语 Joinpoint(连接点): 所谓连接点是指那些被拦截到的点。在 spring 中,这些点指的是方法,因为 spring …...

uni-app--》uni-app的生命周期讲解

&#x1f3cd;️作者简介&#xff1a;大家好&#xff0c;我是亦世凡华、渴望知识储备自己的一名在校大学生 &#x1f6f5;个人主页&#xff1a;亦世凡华、 &#x1f6fa;系列专栏&#xff1a;uni-app &#x1f6b2;座右铭&#xff1a;人生亦可燃烧&#xff0c;亦可腐败&#xf…...

fastp软件介绍

fastp软件介绍1、软件介绍2、重要参数解析2.1 全部参数2.2 使用示例2.3 重要参数详解&#xff08;1&#xff09;UMI去除&#xff08;2&#xff09;质量过滤&#xff08;3&#xff09;长度过滤&#xff08;4&#xff09;低复杂度过滤&#xff08;5&#xff09;adapter过滤&#…...

C++继承相关总结

文章目录前言1.继承的相关概念1.继承概念2.继承的相关语法3.基类和派生类对象赋值转换(赋值兼容规则&#xff09;2.继承中的注意事项1.继承中的作用域2.派生类的默认成员函数1.构造函数与拷贝构造2.赋值重载与析构3.友元关系与静态成员变量3.多继承(菱形继承)1.虚拟继承2.虚拟继…...

【从零开始学习 UVM】8.2、Reporting Infrastructure —— uvm_printer 详解

文章目录 老派风格在UVM中如何完成uvm 风格Table printerTree printerLine printerprint使用print使用条件使用konb更改print配置示例在一个随机验证环境中,数据对象不断地由不同的组件生成和操作,如果能够显示对象的内容,则调试会变得更加容易。 老派风格 传统上,这是通…...

Mybatis、TKMybatis对比

文章目录1.Mybatis&#xff08;1&#xff09;配置文件&#xff08;2&#xff09;实体类&#xff08;3&#xff09;Mapper&#xff08;4&#xff09;mybatis-config.xml2.TKMybatis&#xff08;1&#xff09;配置文件&#xff08;2&#xff09;实体类&#xff08;3&#xff09;M…...

37了解高可用技术方案,如冗余、容灾

高可用性技术方案是指在系统设计和架构中采用一系列措施来确保系统在遇到各种故障和问题时仍能保持持续的可用性&#xff0c;避免因单点故障而导致系统宕机、数据丢失等问题。其中包括冗余和容灾技术。 冗余技术&#xff1a; 冗余技术是指通过增加系统组件的冗余来提高系统可靠…...

jdb调试问题集锦

https://bbs.kanxue.com/thread-210049.htm蓝铁 1 2017-8-25 19:40 4 楼 0 根据提示&#xff0c;可知&#xff0c;出错的地方是&#xff0c;android.app.ActivityThread.handleBindApplication(), 行4,400 查看源码可以发现&#xff0c;代码中指向的是app.onCreate() …...

要和文心一言来一把你画我猜吗?

想和文心一言来一把你画我猜吗&#xff1f; ChatGPT的爆火&#xff0c;让AI对话模型再次走入大众视野。大家在感叹ChatGPT的智能程度时&#xff0c;总会忍不住想&#xff1a;如果我们也有自己的AI对话模型就好了。在社会的压力下&#xff0c;国内的厂商和研究机构也纷纷做出尝试…...

delete[] p->elems和free(p->elems)有什么区别?

delete[]和free()都是释放内存的函数&#xff0c;但它们具有不同的使用方法和适用情况。 delete[] 通常用于释放C中动态分配的数组空间。在使用new[]运算符分配内存时&#xff0c;应使用delete[]运算符来释放分配的内存。delete[] 运算符会调用每个数组元素的析构函数&#xf…...

CAS问题

CAS&#x1f50e;什么是CAS&#x1f50e;伪代码解析&#x1f50e;CAS是如何实现原子性的&#x1f50e;CAS的应用&#x1f33b;实现原子类&#x1f33b;实现自旋锁&#x1f50e;ABA问题&#x1f33b;ABA问题可能引起的BUG&#x1f33b;ABA问题的解决方案&#x1f50e;结尾&#…...

网络编程socket(下)

目录 一、TCP网络程序 1.1 服务端初始化 1.1.1 创建套接字 1.1.2 服务端绑定 1.1.3 服务端监听 1.2 服务端启动 1.2.1 服务端获取连接 1.2.2 服务端处理请求 1.3 客户端初始化 1.4 客户端启动 1.4.1 发起连接 1.4.2 发起请求 1.5 网络测试 1.6 单执行流服务端的…...

OpenLayers 可视化之热力图

注&#xff1a;当前使用的是 ol 5.3.0 版本&#xff0c;天地图使用的key请到天地图官网申请&#xff0c;并替换为自己的key 热力图&#xff08;Heatmap&#xff09;又叫热点图&#xff0c;是一种通过特殊高亮显示事物密度分布、变化趋势的数据可视化技术。采用颜色的深浅来显示…...

零门槛NAS搭建:WinNAS如何让普通电脑秒变私有云?

一、核心优势&#xff1a;专为Windows用户设计的极简NAS WinNAS由深圳耘想存储科技开发&#xff0c;是一款收费低廉但功能全面的Windows NAS工具&#xff0c;主打“无学习成本部署” 。与其他NAS软件相比&#xff0c;其优势在于&#xff1a; 无需硬件改造&#xff1a;将任意W…...

大话软工笔记—需求分析概述

需求分析&#xff0c;就是要对需求调研收集到的资料信息逐个地进行拆分、研究&#xff0c;从大量的不确定“需求”中确定出哪些需求最终要转换为确定的“功能需求”。 需求分析的作用非常重要&#xff0c;后续设计的依据主要来自于需求分析的成果&#xff0c;包括: 项目的目的…...

Xshell远程连接Kali(默认 | 私钥)Note版

前言:xshell远程连接&#xff0c;私钥连接和常规默认连接 任务一 开启ssh服务 service ssh status //查看ssh服务状态 service ssh start //开启ssh服务 update-rc.d ssh enable //开启自启动ssh服务 任务二 修改配置文件 vi /etc/ssh/ssh_config //第一…...

Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility

Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility 1. 实验室环境1.1 实验室环境1.2 小测试 2. The Endor System2.1 部署应用2.2 检查现有策略 3. Cilium 策略实体3.1 创建 allow-all 网络策略3.2 在 Hubble CLI 中验证网络策略源3.3 …...

基于数字孪生的水厂可视化平台建设:架构与实践

分享大纲&#xff1a; 1、数字孪生水厂可视化平台建设背景 2、数字孪生水厂可视化平台建设架构 3、数字孪生水厂可视化平台建设成效 近几年&#xff0c;数字孪生水厂的建设开展的如火如荼。作为提升水厂管理效率、优化资源的调度手段&#xff0c;基于数字孪生的水厂可视化平台的…...

Axios请求超时重发机制

Axios 超时重新请求实现方案 在 Axios 中实现超时重新请求可以通过以下几种方式&#xff1a; 1. 使用拦截器实现自动重试 import axios from axios;// 创建axios实例 const instance axios.create();// 设置超时时间 instance.defaults.timeout 5000;// 最大重试次数 cons…...

关键领域软件测试的突围之路:如何破解安全与效率的平衡难题

在数字化浪潮席卷全球的今天&#xff0c;软件系统已成为国家关键领域的核心战斗力。不同于普通商业软件&#xff0c;这些承载着国家安全使命的软件系统面临着前所未有的质量挑战——如何在确保绝对安全的前提下&#xff0c;实现高效测试与快速迭代&#xff1f;这一命题正考验着…...

面向无人机海岸带生态系统监测的语义分割基准数据集

描述&#xff1a;海岸带生态系统的监测是维护生态平衡和可持续发展的重要任务。语义分割技术在遥感影像中的应用为海岸带生态系统的精准监测提供了有效手段。然而&#xff0c;目前该领域仍面临一个挑战&#xff0c;即缺乏公开的专门面向海岸带生态系统的语义分割基准数据集。受…...

CSS | transition 和 transform的用处和区别

省流总结&#xff1a; transform用于变换/变形&#xff0c;transition是动画控制器 transform 用来对元素进行变形&#xff0c;常见的操作如下&#xff0c;它是立即生效的样式变形属性。 旋转 rotate(角度deg)、平移 translateX(像素px)、缩放 scale(倍数)、倾斜 skewX(角度…...