String的加减运算及Intern()方法的解析

5 篇文章 1 订阅
订阅专栏
本文详细介绍了Java中的String对象、StringBuffer/StringBuilder的区别以及String的内存分配。重点讨论了String的运算细节,如常量与变量的拼接,并通过实例解析了String的Intern()方法的工作原理。通过对源码和实际例子的分析,揭示了Intern()在字符串池中的查找和添加过程,加深了对Java字符串理解。
摘要由CSDN通过智能技术生成

String的加减运算及Intern()方法的解析

这里我们只讨论JDK1.8的内容

一.String的基础知识

1.String和StringBuffer、StringBuilder

String是使用final修饰的,是不可变的字符串对象,内部使用字符对象存储。

//String 的定义     对象地址不可变
public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence {
	//底层的字符数组。  对象的内容不可变
	private final char value[];
    }

StringBuffer 是可变字符序列,线程是安全的,使用append(),insert()等方法,在原对象上拼接别的字符串。

//对象地址不可变
 public final class StringBuffer
    extends AbstractStringBuilder
    implements java.io.Serializable, CharSequence{
    //对象内容可以改变(可以进行添加,拼接等操作)
	private transient char[] toStringCache;
	
	//该类方法很多都是用了  synchronized  锁,所以保证了线程安全性
	@Override
    public synchronized StringBuffer append(String str) {
        toStringCache = null;
        super.append(str);
        return this;
    }
    ……
}

StringBuilder 是可变字符序列,是线程不安全的,使用append(),insert()等方法,在原对象上拼接别的字符串。

//继承于AbstractStringBuilder
public final class StringBuilder
    extends AbstractStringBuilder
    implements java.io.Serializable, CharSequence
{}


abstract class AbstractStringBuilder implements Appendable, CharSequence {
    //char数组
    char[] value;
}

二.String的内存细节

我们知道String的创建有两个基本的方法,一种是直接赋值,一种是直接生成对象。

  1. String s1 = “1”;
  2. String s2 = new String(“2”);
    不同的赋值方法生成的对象在内存中开辟的空间也是不一样的。
    第一种:首先我们回去判断字符串常量"1",在字符串常量池中是否有存在。如果没有我们会直接在字符串常量池中创建该字符串。并把字符串常量池中的地址"1"给变量s1 。
    第二种:先在堆空间创建一个String对象(没有赋值,只是开辟空间)。然后去字符串常量池寻找是否有常量”2“存在,如果不存在则在常量池创建"2",然后在堆空间中给String对象赋值。如果存在,则直接去堆空间中对String对象赋值。
    在这里插入图片描述

三.String的运算细节

我们先看看一段代码

        String s1 = "1";
        String s2 = "2" + "3";
        String s3 = "4" + s1;
        String s4 = s1 + s2;
        
        final String s5 = "5";
        String s6 = "1" + s5;

和一段其class文件的反编译图String拼接细节反编译图

  • 1.我们先看s2的计算过程(stack_05_0 = ldc(“23”); s2 = stack_05_0),是直接读取的"23",这是把"2"+“3"在编译期间计算成一个常量。如s6的计算,因为s5是final修饰的,可以把s5看作一个常量。所以在编译过程中把 “1” + s5 编译成"15”.
  • 2.我们看s3和s4的计算,是在计算前生成一个StringBuilder对象,读取等式右边的值,使用StringBuilder的append()方法,计算拼接字符串,最后使用StringBuilder的toString()方法赋值给s3。s3是常量加上变量。s4是变量加上变量。但是他们最后都是创建一个String对象。

总结:在字符串计算中,

  1. 如果是常量+常量,结果是不会再堆空间生成对象
  2. 如果有变量参与计算,结果是会在堆空间生成对象

结合String的内存情况和计算细节
我们一起来看一道题(理论不如实践):

String str1 = "1";
String str2 = "2";
String str3 = new String("1");
final String str4 = "2";
final String str5 = new String("2");
String str6 = "12";
String str7 = "1" + "2";
String str8 = str1 + "2";
String str9 = str1 + str2;
String str10 = str3 + str4;
String str11 = "1" + str4;
String str12 = "1" + str5;

String str13 = (str1 + str2).intern();

System.out.println("(1)"+ (str1 == str3));  
System.out.println("(2)"+ (str2 == str4));
System.out.println("(3)"+ (str4 == str5));
System.out.println("(4)"+ (str6 == str7));
System.out.println("(5)"+ (str6 == str8));
System.out.println("(6)"+ (str6 == str9));
System.out.println("(7)"+ (str6 == str10));
System.out.println("(8)"+ (str6 == str11));
System.out.println("(9)"+ (str6 == str12));
System.out.println("(10)"+ (str6 == str13));

//注意: “==”   当对象之间比较时,比较的是他们两个中存的对象地址值
//输出(我们一个一个解析)
(1)false	//str1是常量池的对象,str3是堆空间的对象,自然并不会相等。
(2)true		
//我们要注意str4的修饰符final(表示str4不能再指向其他对象或者赋值,
//str4内存的地址或数字不可再被改变),这时str4不是对象是常量
//(编译器发现str4内存的地址是常量池的地址,而且str4又是不可改变的,
//所以编辑器自动优化,把str4当作常量池的对象直接使用)相当于”2“,所以 s2 == "2" 为true
(3)false	
//str5虽然也是被final修饰,但是str5 调用 new String()在堆中生成对象是指,
//这个对象是常量,是不可变的(不允许s5 再指向别的对象),但是str5指向的地址还是在堆内,
//所以 对象(对象地址) == 常量 为false;
(4)true		//编译期间自动处理 常量池地址(”12“) == 常量池地址(”12“) 为 true
(5)false	// 常量池地址 == 堆内地址  为false
(6)false	// 常量池地址 == 堆内地址  为false
(7)false	// 常量池地址 == 堆内地址  为false
(8)true		// str4是常量,所以str11是 常量+常量,所以是 常量池地址 == 常量池地址 为true;
(9)false	// 常量池地址 == 堆内地址  为false
(10)true	//我们就会很疑惑 new String().intern() 是啥?	别急我们继续向下看

反编译的代码图(辅助查看内存变化):
在这里插入图片描述
在这里插入图片描述

四.Intern()方法的作用

我们查看String的源代码看看Intern()的功能:

public native String intern();

…… 尴尬,看不到。
那其官方文档呢?
Two thousand years……

public String intern()
返回字符串对象的规范表示形式。 
一个字符串池,最初是空的,是由类String私下保持。
当intern()的方法被调用时,如果池中已经包含一个字符串相等这String对象由equals(Object)法确定,然后从池中的字符串返回。否则,这String对象添加到池中,一提到这个String对象返回。
因此,对于任意两个字符串s和t,s.intern() == t.intern()是true当且仅当s.equals(t)是true。
所有字符串和字符串值常量表达式是拘留。
字符串字面值是在The Java™ Language Specification部分3.10.5定义。
Returns: 
一个具有与此字符串相同的内容的字符串,但保证是从一个独特的字符串池。

总结就是:会根据当前对象的值,去查看字符串常量池中是否存在该字符串,
有两种情况:

  • 1.如果存在,则返回该字符串在常量池的地址。
  • 2.如果不存在,则把该字符串的地址(堆空间该String()的地址)存放在常量池中。并返回该字符串的地址(堆空间该String()的地址)。以后有需要该值的字符串,获得的也是堆空间该String()的地址

额外知识点(马上会用到):

System.identityHashCode(Object o);身份hash值,是对象在内存中的真实hash值。(调用运行的是object的hashcode()计算方法。无论该object的子类是否重写过hashcode计算)

我们来看看一题(验证第一种情况:如果存在,则返回该字符串在常量池的地址。):

String str2 = new String("1") + new String("1");// + new String("1")
String s3 = "11";
str2 = str2.intern();
System.out.println(s3 == str2);  // true

我们来分析一下该题:

  1. str2等于两个对象相加,会创建一个StringBuilder,执行两次append(new String(“1”)),后调个toString()返回一个String 对象给 Str2。
    所以我们知道在该行执行完后:
    在常量池中有一个”1“的字符串(为什么常量池没有”11“的字符串,因为”11“没有在代码中显式出现,而是StringBuilder对象拼接的char[]数组,直接给Str2对象复制的),堆空间有两个new String(”1“)和一个new String(“11”)对象。
  2. 在执行完String s3 = "11"时。这时字符串常量池会多出一个”11“的字符串。s3存放的就是字符串常量池的"11"的地址。
  3. str2 = str2.intern(); 执行 intern() 方法:会去字符串常量池中查看是由存在 "11"字符串(已经存在,由上一步创建),所以会返回常量池中"11"字符串的地址给str2。
  4. str3 == str2 为true。
    我们调用查看地址的方法看看其内容:
String str2 = new String("1") + new String("1");
System.out.println("str2对象的内存地址:"+System.identityHashCode(str2));

String s3 = "11";
System.out.println("str3对象的内存地址:"+System.identityHashCode(s3));

str2 = str2.intern();
System.out.println("str2.intern()对象的内存地址:"+System.identityHashCode(str2));

System.out.println(s3 == str2);
/*
str2对象的内存地址:1908153060
str3对象的内存地址:116211441
str2.intern()对象的内存地址:116211441
true
*/

我们可以看到 str2.intern()返回的是str3存储的地址,就是常量池中的字符串"11"的地址。

那我们在看看该题的变形(验证第二种情况:如果不存在,则把该字符串的地址……):

String str2 = new String("1") + new String("1");
System.out.println("str2对象的内存地址:"+System.identityHashCode(str2));

str2 = str2.intern();
System.out.println("str2.intern()对象的内存地址:"+System.identityHashCode(str2));

String s3 = "11";
System.out.println("str3对象的内存地址:"+System.identityHashCode(s3));

System.out.println(s3 == str2);

/*
str2对象的内存地址:460141958
str2.intern()对象的内存地址:460141958
str3对象的内存地址:460141958
true
*/

str2一开始的地址就是(堆地址) 460141958 。但是 str2.intern();返回也是这个地址。这就符合第二种情况:如果字符串常量池不存在"11",就会在**字符串常量池创建一个对象保存 460141958(堆地址) **,在str3赋值时,发现常量池中已经有"11"字符串,就把字符串常量池"11"对象的内容【460141958(堆地址)】给了str3。所以 str3对象的内存地址:460141958。

最后一题(练习练习,没有解析):

String s = new String("1");		//执行完这一行,在常量池和堆空间中均有了”1“这个值,s保存的是堆空间的地址值。
s.intern();
String s2 = "1";
System.out.println(s == s2);
 
String s3 = new String("1") + new String("1");
s3.intern();
String s4 = "11";
System.out.println(s3 == s4);
//
//false
//true
java高级工程师/技术专家面试系列九之 jvm与性能优化
java技术专家全栈成长之路
03-18 541
1. 描述一下 JVM 加载 Class 文件的过程逻辑 Java中所有类的编译与运行,都需要由类加载器装载到JVM中才能运行。[类加载器]本身也是一个类,而它的工作就是把class文件从硬盘读取到内存中。在写程序的时候,我们几乎不需要关心类的加载,因为这些都是隐式通过JVM底层装载的,另外我们也可以显式的加载所需要的类,比如Spring里面的反射。 Java类的加载是动态的,它并不会一次性将所有类全部加载后再运行,而是保证程序运行的基础类(像是基类)完全加载到jvm中,至于其他类,则在需要的时候才加载
【算法】大数(string)的加法与减法
进阶之路
04-06 8007
我们在做题的时候,处理字符串的时候,通常会碰到字符串加减法,它们其实就是一个模板,只要我们多理解,就能快速的写出大数的加法,也就是string对象的加法。会了加法乘法就肯定不用说了。 我们主要讲string对象加法和 除法,因为减法就是在除法的过程中得以体现的。 string对象的加法 算法思想: 1. 2. 3. 4. string add(string a, string b) { b =...
JAVA--OOP思想(1)
weixin_50563955的博客
11-26 288
面向对象1 1.1 面向对象 1.1.1 概念 所谓的面向对象是一种编程思想,通过这种思想可以把生活中的复杂事情变得简单化,从原来的执行者变成了指挥者,面向对象是基于面向过程而言的。 我们经常说的面向对象的编程实现(OOP,Object Oriented Programming) 面向过程强调的是过程,例如: 1、打开冰箱 2、把大象放进去 3、关上冰箱 面向对象强调结果,例如: 1、 饿了,去平台点餐,这个动作就是面向对象。你没有去市场买菜洗菜做饭。。。只要有app就可以了。 2、
javastring类型的日期相减
最新发布
weixin_41357584的博客
08-01 102
给大家整理了一些有关【字符串,Java】的项目学习资料(附讲解~~):https://edu.51cto.com/course/35079.htmlhttps://edu.51cto.com/course/35714.htmlJavaString类型日期相减的实现 在Java编程中,日期和时间的处理是一个常见而重要的...
string类型加减_【常用类方法String
weixin_36389335的博客
01-25 5177
整理一下String类的基本操作方法方法名均省略public修饰符)字符与字符串构造方法String(char[] value)将字符数组变为String类对象String(char[] value, int offset, int count)将部分字符数组变为String普通方法:char charAt(int index)返回指定索引对应的字符信息(注意,字符串的索引下标从0开始)cha...
JavaOOP思想
he_zizhi的专栏
04-11 181
一:封装 1、为什么需要封装? 封装使数据更安全,便于控制,外部需要关注的内容减,只需要关注公开出来的接口,还可提高代码复用, 2、.封装包括两方面:包括数据封装和功能封装(实现的封装) (1)隐藏实现: 方法内部实现外部无需关注,只提供给外部访问接口。 隐藏数据: 将属性私有化,对外提供公有的方法(getter和setter)访问私有属性。 另外还可以封装变化。 封...
5道阿里面试题,彻底拿捏String底层原理
wdj_yyds的博客
02-18 276
String字符串是我们日常工作中常用的一个类,在面试中也是高频考点,这里Hydra精心总结了一波常见但也有点烧脑的String面试题,一共5道题,难度从简到难,来一起来看看你能做对几道吧。 本文基于jdk8版本中的String进行讨论,文章例子中的代码运行结果基于Java 1.8.0_261-b12 第1题,奇怪的 nullnull 下面这段代码最终会打印什么? public class Test1 { private static String s1; private st
【搞定Java基础】第4篇:Java 中的 String 类详解 【解惑篇】
Java学习
01-18 491
本文转发自: 1、https://blog.csdn.net/justloveyou_/article/details/52556427 2、https://blog.csdn.net/justloveyou_/article/details/60983034 本文目录: 一、Java 内存模型与常量池 二、常量与变量 三、String 类的定义与基础 四、String 的不可变性 ...
Java中高级面试题总览(一)
热门推荐
击水三千里的专栏
03-29 2万+
高频面试题深入剖析
【JVM源码解析】模板解释器解释执行Java字节码指令(上)
HeapDump性能社区的博客
11-25 1039
本文由HeapDump性能社区首席讲师鸠摩(马智)授权整理发布 第17章-x86-64寄存器 不同的CPU都能够解释的机器语言的体系称为指令集架构(ISA,Instruction Set Architecture),也可以称为指令集(instruction set)。Intel将x86系列CPU之中的32位CPU指令集架构称为IA-32,IA是“Intel Architecture”的简称,也可以称为i386、x86-32。AMD等于Intell提出了x86系列的64位扩展,所以由AMD设计的x86系列.
JavaOOP思想总结
09-26
JavaOOP面向对象,JavaOOP面向对象,JavaOOP面向对象,JavaOOP面向对象,JavaOOP面向对象,JavaOOP面向对象,
Java OOP编程思想学习之我见
07-30
Java OOP编程思想学习之我见
string类型加减_Redis系列-数据类型String
weixin_35940587的博客
01-25 942
redis 数据存储格式redis 存储的数据格式是一个映射的关系。自身是一个 Map,其中所有的数据都是采用 key : value 的形式存储数据类型指的是存储的数据的类型,也就是 value 部分的类型,key 部分永远都是字符串在其存储的空间中如果几个数据,必然会有相应的key出现。如下图,name对应 张三 , sex 对应 man 。可以理解为一个名称对应一个数据,一个key对应一个v...
Java OOP 思想
weixin_45713608的博客
09-03 189
JAVA OOP 类和对象
java里oop思想_Java OOP 思想解析
weixin_29256771的博客
02-27 399
因为有着一年半的iOS开发经验(OC也是一门面向对象的语言)所以在对Java的面向对象的理解上也是有着自己的理解,今天就和大家分享一下。面向对象中最为重要的三大思想就是:继承、封装、多态。本文将以一个实例场景来分析Java中的OOP。现有一个场景:学校人员管理。首先分析出此场景所包含的角色类别:学生,老师,校长。那么我们可以为每个角色类别创建对应的类(具体相同特征或者行为的一种抽象)。学生(Stu...
JavaOOP思想及内存解析
自学之路←_←
12-17 239
前言         面向对象最关键的两个词汇是类与对象,实质上可以将类看作对象的抽象,它定义了对象所具有的属性和方法。学习 Java 语言必须掌握类与对象,这样可以从深层次理解 Java 这种面向对象语言的幵发理念。因此,掌握类与对象是学习 Java 语言的基础,可以使开发人员更好、更快地掌握 Java 编程思想与编...
java里oop思想_JAVA中的OOP思想
weixin_29380121的博客
02-27 280
转载请标明出处:如果之前没有接触过OO(面向对象)语言的人一开始理解OO确实需要一段时间,而且这种思想非常重要,比语言本身更重要。尤其那些之前只看过c语言,直接过渡到java的人。对于熟悉C++来说,java的实现和C++还有些不同。有兴趣可以了解一下C++面向对象的实现。1.为什么要引入OO这种思想回答这个问题,必须知道OO之前的编程思想:面向过程的方式。1.1 面向过程与面向对象面向过程:Pr...
JVM实战:深入解析String类与intern方法
"深入理解JVM实战篇-探讨String类的使用和intern()方法" 深入理解JVM实战篇,特别是关于String类的讨论,对于Java开发者来说至关重要。String类在Java编程中扮演着核心角色,因为字符串是经常使用的数据类型。在...
写文章

热门文章

  • String的加减运算及Intern()方法的解析 4041
  • java中的自增(++),自减(--)——踩坑 648
  • static 对 子类、父类加载初始化顺序的影响 443
  • java的基本数据类型及其包装类 276
  • java集合-ArrayList全解 256

分类专栏

  • java基础 5篇
  • java基础——java集合 4篇
  • 数据结构与算法 4篇

最新评论

  • java中的自增(++),自减(--)——踩坑

    miracle3014: 👍

  • HashMap有趣的分析

    webmote: 送我上前排!有空来看我! 拜访我

  • String的加减运算及Intern()方法的解析

    webmote: 不错,谢谢楼主分享,有空来看看我呀! 棒棒哒

  • String的加减运算及Intern()方法的解析

    不吃西红柿丶: 很棒,期待大佬后续作品~

  • java中的自增(++),自减(--)——踩坑

    不正经的kimol君: 好文,鉴定完毕!

大家在看

  • Go入门指南-1.2主要特性与发展的环境和影响因素 1
  • 变量与基本数据类型 890
  • C语言结构体数组 java静动数组及问题 90
  • Linux常用命令大全超详细知识点概览 1080
  • Springboot知识点总结 658

最新文章

  • Java的String不可变字符串身份的讨论
  • HashMap有趣的分析
  • LinkedList的源码全解
2021年1篇
2020年12篇

目录

目录

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值

玻璃钢生产厂家蚂蚁玻璃钢卡通雕塑厂家深圳商业街玻璃钢雕塑批发睢阳玻璃钢雕塑厂家商场美陈礼盒江苏定制玻璃钢雕塑价格合理祥符玻璃钢雕塑价格电动玻璃钢雕塑玻璃钢人物雕塑价格枣庄校园玻璃钢雕塑安装绵阳玻璃钢卡通雕塑价格德宏玻璃钢雕塑批发零售白银人物玻璃钢雕塑厂家玻璃钢雕塑货真价实衢州特色玻璃钢雕塑销售厂家泰州五一商场美陈咸宁玻璃钢花盆花器通化玻璃钢景观雕塑青海玻璃钢人物雕塑厂家河南通道商场美陈费用商场新年美陈适合挂什么镜面玻璃钢卡通雕塑定做价格雕塑 石膏 玻璃钢信阳玻璃钢浮雕雕塑厂家贵州玻璃钢雕塑价格多少钱辽宁玻璃钢卡通雕塑猴子陕西抽象玻璃钢雕塑价位西青玻璃钢雕塑公司玻璃钢龙虾雕塑视频长春人物玻璃钢雕塑厂家深圳大型商场美陈销售香港通过《维护国家安全条例》两大学生合买彩票中奖一人不认账让美丽中国“从细节出发”19岁小伙救下5人后溺亡 多方发声单亲妈妈陷入热恋 14岁儿子报警汪小菲曝离婚始末遭遇山火的松茸之乡雅江山火三名扑火人员牺牲系谣言何赛飞追着代拍打萧美琴窜访捷克 外交部回应卫健委通报少年有偿捐血浆16次猝死手机成瘾是影响睡眠质量重要因素高校汽车撞人致3死16伤 司机系学生315晚会后胖东来又人满为患了小米汽车超级工厂正式揭幕中国拥有亿元资产的家庭达13.3万户周杰伦一审败诉网易男孩8年未见母亲被告知被遗忘许家印被限制高消费饲养员用铁锨驱打大熊猫被辞退男子被猫抓伤后确诊“猫抓病”特朗普无法缴纳4.54亿美元罚金倪萍分享减重40斤方法联合利华开始重组张家界的山上“长”满了韩国人?张立群任西安交通大学校长杨倩无缘巴黎奥运“重生之我在北大当嫡校长”黑马情侣提车了专访95后高颜值猪保姆考生莫言也上北大硕士复试名单了网友洛杉矶偶遇贾玲专家建议不必谈骨泥色变沉迷短剧的人就像掉进了杀猪盘奥巴马现身唐宁街 黑色着装引猜测七年后宇文玥被薅头发捞上岸事业单位女子向同事水杯投不明物质凯特王妃现身!外出购物视频曝光河南驻马店通报西平中学跳楼事件王树国卸任西安交大校长 师生送别恒大被罚41.75亿到底怎么缴男子被流浪猫绊倒 投喂者赔24万房客欠租失踪 房东直发愁西双版纳热带植物园回应蜉蝣大爆发钱人豪晒法院裁定实锤抄袭外国人感慨凌晨的中国很安全胖东来员工每周单休无小长假白宫:哈马斯三号人物被杀测试车高速逃费 小米:已补缴老人退休金被冒领16年 金额超20万

玻璃钢生产厂家 XML地图 TXT地图 虚拟主机 SEO 网站制作 网站优化