Java创建字符串的两种方式在地址上的区别

简介: Java创建字符串的两种方式在地址上的区别

一、JAVA中字符串的两种创建方式


我们知道,在Java中有两种创建字符串对象的方式:

1)采用直接赋值的方式赋值


String str1 = "abc";

       采用这种方法去创建字符串时,JVM会在方法区的字符串常量池中寻找这个字符串是否存在,如果存在则不去创建,让创建的对象直接引用其在字符串常量池中的地址;如果不存在则在字符串常量池中创建这个字符串并且返回这个字符串在常量池中的地址。

image.png

编辑

2)采用new关键字新建一个字符串对象


String str2 = new String("abc");
复制代码

       采用new关键字新建一个字符串对象时,JVM首先在字符串池中查找有没有"abc"这个字符串如果有,则不在池中再去创建"abc"这个对象了,直接在堆中创建一个"abc"字符串对象,然后将堆中的这个"abc"对象的地址返回赋给引用str,这样,str就指向了堆中创建的这个"abc"字符串对象;如果没有,则首先在字符串池中创建一个"abc"字符串对象,然后再在堆中创建一个"abc"字符串对象,然后将堆中这个"abc"字符串对象的地址返回赋给str引用,这样,str指向了堆中创建的这个"abc"字符串对象。

注意:这种方法本质是在堆区引用字符串常量池中的地址,每次new的对象,在堆上都会创建一个新的对象指向常量池。

image.png

编辑

这两种创建方法其实在创建性能上和访问上是有区别的。(堆区创建带来的性能开销)

二、两种创建方法字符串指向比较


public class Demo1 {
    public static void main(String[] args) {
        String str1 = "abc";
        String str2 = new String("abc");
        String str3 = "abc";
        System.out.println(str1.equals(str2));
        System.out.println(str1 == str2);
        System.out.println(str1 == str3);
    }
}

image.png编辑

这两种方法创建出的字符串虽然内容是一样的,但指向是不一样的。str1和str3直接指向的是常量池的地址,str2指向堆的地址。(参考上面两个图)。

再看下面的代码:

public class Demo1 {
    public static void main(String[] args) {
        String str1 = "abcdef";
        String str2 = "abc";
        String str3 = "def";
        String str4 = "abc" + "def";
        String str5 = str2+str3;
        String str6 = new String("abc"+"def");
        System.out.println(str1 == str4);
        System.out.println(str1 == str5);
        System.out.println(str1 == str6);
    }
}

image.png编辑

这里的str1 == str4很好理解,“abc” + “def”这一步在编译期间会合并成“abcdef”所以输出true;str1 == str5这里的str5出现这样的结果,别的一些说法认为只有使用引号包含文本的方式创建的String对象之间使用“+”连接产生的新对象才会被加入字符串池中。对于所有包含new方式新建对象和直接运用字符串变量的“+”连接表达式,它所产生的新对象都不会被加入字符串池中,都放在了堆内存中。

我对str5的理解是因为str2和str3以及是存在的对象了,所以寻找的第一位置是堆内存所以它并不会再进一步去其对应的常量池中寻找拿出再去拼接这两段字符串。所以只能将他俩在堆区完成操作并且放在堆中导致返回结果是false。

指向地址查看:


public class Demo1 {
    public static void main(String[] args) {
        String str1 = "abcdef";
        String str2 = "abc";
        String str3 = "def";
        String str4 = "abc" + "def";
        String str5 = str2+str3;
        System.out.println(System.identityHashCode(str1));
        System.out.println(System.identityHashCode(str2));
        System.out.println(System.identityHashCode(str3));
        System.out.println(System.identityHashCode(str4));
        System.out.println(System.identityHashCode(str5));
    }
}

image.png

编辑

这样就很明显的看出这些创建方式对象的引用是什么了。

总结:


       new创建出的对象指向均不相等,字符串的创建无论是哪种方式,都需要先在字符串常量池中寻找该字符串是否存在。

如果有不正确的地方请指出,欢迎一起讨论!


相关文章
|
26天前
|
安全 Java API
【Java字符串操作秘籍】StringBuffer与StringBuilder的终极对决!
【8月更文挑战第25天】在Java中处理字符串时,经常需要修改字符串,但由于`String`对象的不可变性,频繁修改会导致内存浪费和性能下降。为此,Java提供了`StringBuffer`和`StringBuilder`两个类来操作可变字符串序列。`StringBuffer`是线程安全的,适用于多线程环境,但性能略低;`StringBuilder`非线程安全,但在单线程环境中性能更优。两者基本用法相似,通过`append`等方法构建和修改字符串。
44 1
|
2天前
|
Java
Java实现:将带时区的时间字符串转换为LocalDateTime对象
通过上述方法,你可以将带时区的时间字符串准确地转换为 `LocalDateTime`对象,这对于处理不需要时区信息的日期和时间场景非常有用。
39 4
|
5天前
|
机器学习/深度学习 人工智能 安全
python和Java的区别以及特性
Python:适合快速开发、易于维护、学习成本低、灵活高效。如果你需要快速上手,写脚本、数据处理、做点机器学习,Python就是你的首选。 Java:适合大型项目、企业级应用,性能要求较高的场景。它类型安全、跨平台能力强,而且有丰富的生态,适合更复杂和规模化的开发。
14 3
|
11天前
|
算法 Oracle Java
Java字符串拼接技术演进及阿里巴巴的贡献
本文主要讲述了Java字符串拼接技术的演进历程,以及阿里巴巴贡献的最新实现 PR 20273。
|
17天前
|
算法 Oracle Java
Java字符串拼接技术演进及阿里巴巴的贡献
本文主要讲述了Java字符串拼接技术的演进历程,以及阿里巴巴贡献的最新实现 PR 20273。
|
23天前
|
XML JSON 前端开发
Java @RequestParam和@RequestBody的区别是什么?
【8月更文挑战第28天】Java @RequestParam和@RequestBody的区别是什么?
27 5
|
28天前
|
存储 Java API
|
20天前
|
API C# 开发者
WPF图形绘制大师指南:GDI+与Direct2D完美融合,带你玩转高性能图形处理秘籍!
【8月更文挑战第31天】GDI+与Direct2D的结合为WPF图形绘制提供了强大的工具集。通过合理地使用这两种技术,开发者可以创造出性能优异且视觉效果丰富的WPF应用程序。在实际应用中,开发者应根据项目需求和技术背景,权衡利弊,选择最合适的技术方案。
33 0