new String(“abc“) 创建了几个对象?

一、概述

本文分析了以下3个问题:

  1. new String("abc") 创建对象数量问题。
  2. String对象在什么情况下会复用。
  3. String对象,在什么情况下会复用常量池中Stringvalue对象。

二、创建对象数量

通过分析字节码,我们可以看到仅常量池中就有21个对象,当然其中有一些属于main方法和所在类引入的对象。
查看String类的源码,我们还可以看到有大量的方法、变量还有一个CaseInsensitiveComparator类。
因此 new String("abc") 这句代码至少创建了几十个对象。

1、代码

public class T {
    public static void main(String[] args) {
        String b = new String("abc");
    }
}

2、字节码

C:\Users\abc\Desktop\test>javap -v T
Classfile /C:/Users/abc/Desktop/test/T.class
  Last modified 2020-4-27; size 326 bytes
  MD5 checksum 579cb2cb8a365cae08739813ca28971b
  Compiled from "T.java"
public class T
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #6.#15         // java/lang/Object."<init>":()V
   #2 = Class              #16            // java/lang/String
   #3 = String             #17            // abc
   #4 = Methodref          #2.#18         // java/lang/String."<init>":(Ljava/lang/String;)V
   #5 = Class              #19            // T
   #6 = Class              #20            // java/lang/Object
   #7 = Utf8               <init>
   #8 = Utf8               ()V
   #9 = Utf8               Code
  #10 = Utf8               LineNumberTable
  #11 = Utf8               main
  #12 = Utf8               ([Ljava/lang/String;)V
  #13 = Utf8               SourceFile
  #14 = Utf8               T.java
  #15 = NameAndType        #7:#8          // "<init>":()V
  #16 = Utf8               java/lang/String
  #17 = Utf8               abc
  #18 = NameAndType        #7:#21         // "<init>":(Ljava/lang/String;)V
  #19 = Utf8               T
  #20 = Utf8               java/lang/Object
  #21 = Utf8               (Ljava/lang/String;)V
{
  public T();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: return
      LineNumberTable:
        line 1: 0

  public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=3, locals=2, args_size=1
         0: new           #2                  // class java/lang/String
         3: dup
         4: ldc           #3                  // String abc
         6: invokespecial #4                  // Method java/lang/String."<init>":(Ljava/lang/String;)V
         9: astore_1
        10: return
      LineNumberTable:
        line 3: 0
        line 4: 10
}
SourceFile: "T.java"

三、String对象复用案例

public static void main(String[] args) {
    try {
        String str1 = "abc";
        String str2 = "abc";
        //结果为true,说明是同一String对象
        System.out.println(str1 == str2);

        //结果为false,说明不是同一String对象
        String str3 = new String("abc");
        System.out.println(str1 == str3);
    } catch (Exception e) {
        e.printStackTrace();
    }
}

四、String复用value案例

1、案例一(value对象相同)

比较两个String结果为false。说明 str2 的对象和 str1 不是同一个。
比较两个String中value结果为true。说明String对象中的value其实还是同一个。
new String(“abc”) 使用了常量池中 Stringvalue 对象

    public static void main(String[] args) {
        try {
            String str1 = "abc";
            String str2 = new String("abc");
            // 比较两个String(结果为false。说明 str2 对象和 str1 不是同一个。)
            System.out.println(str1 == str2);

            Field field1 = getField(str1, "value");
            Field field2 = getField(str2, "value");
            Object value1 = field1.get(str1);
            Object value2 = field2.get(str2);
            // 比较两个String中value(结果为true。说明String对象中的value其实还是同一个。)
            System.out.println(value1 == value2);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private static Field getField(Object obj, String fieldName) throws NoSuchFieldException {
        Class cl = obj.getClass();
        Field valueField = cl.getDeclaredField(fieldName);
        valueField.setAccessible(true);
        return valueField;
    }

2、案例二(value对象不同)

我们换一下str2的赋值方式,改为程序运行过程中输入。
此时,比较两个String中value结果为false;说明String对象中的value不是同一个了。
程序运行时,输入的 str2 没有使用常量池中 Stringvalue 对象

    public static void main(String[] args) {
        try {
            String str1 = "abc";
            //String str2 = new String("abc");
            BufferedReader stdin =new BufferedReader(new InputStreamReader(System.in));
            System.out.print("Enter a line:");
            String str2 = stdin.readLine();

            // 比较两个String(结果为false。说明 str2 对象和 str1 不是同一个。)
            System.out.println(str1 == str2);

            Field field1 = getField(str1, "value");
            Field field2 = getField(str2, "value");
            Object value1 = field1.get(str1);
            Object value2 = field2.get(str2);
            // 比较两个String中value(结果为false。说明String对象中的value不是同一个。)
            System.out.println(value1 == value2);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值