Java中String显式声明的对象创建问题

转载请注明出处:http://blog.csdn.net/infant09/article/details/77822913

关键词:java; String; 字面量; 显式; 声明; 对象; 显示; 直接声明; 直接定义

String对象的几种创建方式


String类是Java中比较特殊的一类。Java在设计时为了提高String类的使用效率,使用String Pool的机制进行String管理。

String对象有以下几种声明方式:

  • 显式声明(使用字面量创建对象,String literals):

    String s = "abc";
  • new关键字声明:

    //通过String创建新的String对象,此方法是redundant
    String s0 = new String("123");
    
    //通过char数组来生成String
    char c[] = {48, 49};
    String s1 = new String(c);
    
    //通过int来生成String
    int i = 123;
    String s2 = String.valueOf(i);
    
    //other function ......
  • 字符串拼接(使用字面量创建对象):

    String s = "123" + "456";

问题提出


通过new关键字声明,实际上是调用了String类的构造方法。但是通过双引号进行显式声明,是如何创建对象的呢?

Java的基本类型,可以直接显式声明,但是String不是基本类型,显然是编译器隐藏了一些细节。

问题解决


String源码

通过阅读String类的源码,可以发现这样一段话:

 * <blockquote><pre>
 *     String str = "abc";
 * </pre></blockquote><p>
 * is equivalent to:
 * <blockquote><pre>
 *     char data[] = {'a', 'b', 'c'};
 *     String str = new String(data);
 * </pre></blockquote><p>

因此我们可以得知,当使用String str = "abc"声明时,等价于首先创建了char数组,然后调用new String的构造方法。

当然,这只是“等价于”(equivalent),编译器做了一些处理。显式调用String str = "abc"和调用char data[] = {'a', 'b', 'c'}; String str = new String(data);是不一样的过程。

bytecode理解

  1. 显式调用

    package Test;
    
    public class StringTest {
    
        public static void main(String[] args) {
            String s = "abc";
        }
    }

    使用$ javap -c StringTest.class查看编译后的class文件:

    public class Test.StringTest {
    public Test.StringTest();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return
    
    public static void main(java.lang.String[]);
    Code:
       0: ldc           #2                  // String abc
       2: astore_1
       3: return
    }
    

    根据字符串池(String Pool)的机制,String str = "abc"会先在常量池里的字符串池查找"abc"对象,如果没有则创建;然后在栈(stack)中创建str引用,直接指向String pool中的"abc"对象。

  2. new关键字声明

    package Test;
    
    public class StringTest {
    
        public static void main(String[] args) {
            char c[] = {'a', 'b', 'c'};
            String s = new String(c);
        }
    }
    

    字节码如下:

    public class Test.StringTest {
    public Test.StringTest();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return
    
    public static void main(java.lang.String[]);
    Code:
       0: iconst_3
       1: newarray       char
       3: dup
       4: iconst_0
       5: bipush        97
       7: castore
       8: dup
       9: iconst_1
      10: bipush        98
      12: castore
      13: dup
      14: iconst_2
      15: bipush        99
      17: castore
      18: astore_1
      19: new           #2                  // class java/lang/String
      22: dup
      23: aload_1
      24: invokespecial #3                  // Method java/lang/String."<init>":([C)V
      27: astore_2
      28: return
    }
    

    可以首先在堆(heap)中创建对象,然后调用String类的构造方法。当然,调用构造方法的过程中,会在String pool里查找或创建"abc"对象,然后再根据这个对象去heap中创建对象。

这就是显式声明字符串的过程。

其他问题

  • 字符串常量池究竟在JVM的哪里?
  • String s = new String(“abc”) + “abc”,创建了多少个对象?以及其他类似问题

参考文献

https://tech.meituan.com/in_depth_understanding_string_intern.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值