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

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


相关文章
|
23小时前
|
Java
Java获取字符串最后一位
【5月更文挑战第9天】Java获取字符串最后一位
14 5
|
1天前
|
Java 开发框架 XML
JDK、JRE、Java SE、Java EE和Java ME有什么区别?
JDK、JRE、Java SE、Java EE和Java ME有什么区别?
|
1天前
|
Java
java一分钟之-字符流与字节流的区别
【5月更文挑战第11天】Java的输入输出通过流操作,分为字符流和字节流。字节流处理二进制数据,如图片、音频,基类是`InputStream`和`OutputStream`;字符流处理文本,基类是`Reader`和`Writer`。字符流涉及编码转换,字节流不涉及。易错点包括乱码(需指定编码)、混用流类型和忘记关闭流。示例展示了字节流和字符流读文件。理解区别并注意编码和资源管理可提高代码质量。
32 3
|
2天前
|
存储 Java 索引
【JAVA基础篇教学】第十一篇:Java中字符串操作详解
【JAVA基础篇教学】第十一篇:Java中字符串操作详解
|
3天前
|
Java
代码实例演示Java字符串与输入流互转
代码实例演示Java字符串与输入流互转
|
3天前
|
安全 Java 编译器
Java中String、StringBuilder和StringBuffer的区别
Java中String、StringBuilder和StringBuffer的区别
|
11天前
|
传感器 数据采集 网络协议
Java串口通信:从十六进制字符串到字节数组的正确转换与发送
Java串口通信:从十六进制字符串到字节数组的正确转换与发送
30 4
|
12天前
|
Java
Java中 a+=b和a=a+b有什么区别?
Java中 a+=b和a=a+b有什么区别?
|
12天前
|
Java
在Java中,如何将字符串转换为浮点数?
【4月更文挑战第30天】在Java中,如何将字符串转换为浮点数?
17 0
|
12天前
|
Java 开发者
Java中三种Set的实现类的用法和区别
Java中三种Set的实现类的用法和区别