字符串的创建到底有几个对象产生

直接使用字面量

String a = "98374";

这种情况下,在编译时就对常量池进行判断是否存在该字符串.编译期的常量池是静态常量池,如果不存在该字符串,则在常量池中创建该字符串的对象,并返回给该变量.
所以:

String a = "98374";
String b = "98374";

只创建了一个对象

使用new方式创建字符串

String a = new String("98374");

这种情况下,因为使用了new,所以不能在编译时期确定.它的流程是,先判断常量池中是否有该字符串,如果不存在该字符串,则在常量池中创建该字符串的对象.然后,注意,然后是在堆里面复制一个这个字符串对象,然后把堆里面的地址返回给该变量而不是常量池中的对象地址.这是由new的特性决定的.
所以对于new方法来说,当常量池中没有这个字符串的时候,创建两个对象,一个常量池中的,一个堆中的.当常量池中有这个字符串的时候,只创建一个对象
所以:

String a = new String("98374");
String b= new String("98374");

这种情况下就创建了三个对象.

使用+号创建字符串

这个要分两种情况:

  1. 场景1

    String a = "9"+8+"3"+"7"+4;
    

    所有用于连接的都是字面量,所以也就是说可以在编译时期确定,当字符串连接完成以后会判断是否常量池中有该字符串,如果没有则在常量池中创建一个字符串,然后返回该字符串.

  2. String a = "9"+8+"3"+new String("7")+4;
    

    有一个new生成的子串,所以无法在编译器确定,那么jvm是如何做的呢,创建一个StringBuilder对象,然后挨个append每个子串,最后返回StringBuilder的toString方法,这其中生成的对象要看有几个子串,因为每次append的时候都是使用new String()生成的子串然后拼接的,当然了如果前面有字面量会提前编译.
    上面的代码就相当于:

      StringBuilder sb = new StringBuilder("983");//一个对象
      sb.append(new String("7"));//两个对象
      sb.append(new String(String.valueOf(4)));//4个对象
      return sb.toString();//5个对象
    

使用valueOf创建字符串

它的源码为:

   public static String valueOf(Object obj) {
        return (obj == null) ? "null" : obj.toString();
    }

也即是调用对象的toString方法,这个针对不同对象有不同的实现.并不一致.

  1. Object的toString方法
public String toString() {
    return getClass().getName() + "@" + Integer.toHexString(hashCode());
}

而Integer.toHexString(hashCode());最终会调用

private static String toUnsignedString0(int val, int shift) {
    // assert shift > 0 && shift <=5 : "Illegal shift value";
    int mag = Integer.SIZE - Integer.numberOfLeadingZeros(val);
    int chars = Math.max(((mag + (shift - 1)) / shift), 1);
    char[] buf = new char[chars];

    formatUnsignedInt(val, shift, buf, 0, chars);

    // Use special constructor which takes over "buf".
    return new String(buf, true);
}

所以还是调用了new方法创建对象

  1. 如果其他的类自己重写了toString方法就要看具体实现方式了,并不一致.

测试代码

/**
 * @program: infoalgorithm
 * @description: 测试String的创建问题
 * @author: zhouzhilong
 * @create: 2019-07-10 15:26
 **/
public class StringTest {
    /**
     * logger
     */
    private static final Logger LOGGER = LoggerFactory.getLogger(StringTest.class);

    @Test
    public void test() {
        /*直接使用字面量赋值*/
        String m = "89734";
        String n = "89734";
        LOGGER.debug("m == n :{}", m == n);//true

        /*字面量与new对比*/
        m = "89734";
        n = new String("89734");
        LOGGER.debug("m == n :{}", m == n);//false


        /*new 与new 对比*/
        m = new String("89734");
        n = new String("89734");
        LOGGER.debug("m == n :{}", m == n);//false


        /*String.valueOf与字面量对比*/
        m = "89734";
        n = String.valueOf(89734);
        LOGGER.debug("m == n :{}", m == n);//false



        /* +号 连接符*/
        m = "89734";
        n = "8" + "9" + 7 + "3" + "4";
        LOGGER.debug("m == n :{}", m == n);//true

        /* +号 连接符 使用变量*/
        m = "89734";
        n = "8" + "9" + 7 + new String("3") + "4";
        LOGGER.debug("m == n :{}", m == n);//false

        /* 字面量与toString()*/
        m = "89734";
        n = new Integer(89374).toString();
        LOGGER.debug("m == n :{}", m == n);//false
    }
}

  • 6
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值