java String(二)—— 关于String类的一些查询与思考

1、看到的一篇关于String类的讨论与思考

https://bbs.csdn.net/topics/370250506?page=2

public class Test {
 
    private static void test(String s) {
        s = s.concat("123");
    }
     
    private static void test2(StringBuilder sb) {
        sb.append("123");
    }
     
    public static void main(String[] args) {
        String t = "hello";
        test(t);
        System.out.println(t);
         
        StringBuilder sb = new StringBuilder("hello");
        test2(sb);
        System.out.println(sb.toString());
    }
}

输出结果:

hello
hello123

该楼主的解释为:
在这里插入图片描述

我按照自己的理解,画了下图:

在这里插入图片描述
后来看到对该段代码的反驳:
在这里插入图片描述
在这里插入图片描述在这里插入图片描述
在这里插入图片描述

public class Test {
 
    private static void test(String s) {
       // s = s.concat("123");
    	s = null;
    }
     
    private static void test2(StringBuilder sb) {
        //sb.append("123");
    	sb = null;
    }
     
    public static void main(String[] args) {
        String t = "hello";
        test(t);
        System.out.println(t);
         
        StringBuilder tb = new StringBuilder("hello");
        test2(tb);
        System.out.println(sb.toString());
    }
}

输出结果:

hello
hello

2、别再问我 new 字符串创建了几个对象了!我来证明给你看!

https://juejin.cn/post/6844904129752465416
在这里插入图片描述
我的理解
    因为String中是使用char[]数组来存储字符串的,且该数组变量被定义为final,所以被放置到字符串常量池中。(这个理解貌似是错误的。。https://juejin.cn/post/6844904191324864520#comment
    而StringBuilder中用来存储字符串的char[]数组,并未定义为final类型,所以StringBuilder中声明的字符串并不会被放置到常量池中,且其字符串的值是可以被更改的,相当于char[] 数组可以被更改。

3、字符串常量池

https://juejin.cn/post/6855574934698229768
在这里插入图片描述

4、StringBuffer与StringBuilder

https://zhuanlan.zhihu.com/p/76303946

    String对象一旦创建后,String中的内容是不能够改变的,每次改变String都会创建新的对象。而StringBuffer和StringBuilder的内容却是能够动态改变的。StringBuffer和StringBuilder的区别在于StringBuffer是线程安全的(StringBuffer中的绝大部分都加了同步关键字),而StringBuilder是线程不安全的。因为StringBuilder是线程不安全的,所以其运行效率会更高。如果一个字符串是在方法里面定义的话,这种情况仅仅可能有一个线程访问它,不存在不安全的因素,这时推荐使用StringBuilder。如果一个实例变量是在类里面定义的,并且在多线程下会访问到,这时最好使用StringBuffer。

5、从字节码和 JVM 内存结构的角度来看一道面试题

https://juejin.cn/post/6844904191324864520

6、关于final的例子

final只对引用的“值”(即内存地址)有效,它迫使引用只能指向初始指向的那个对象,改变它的指向会导致编译期错误。

final StringBuffer a = new StringBuffer(111);
final StringBuffer b = new StringBuffer(222);
a = b;  //编译不通过
  • final不可变
  • final是针对stack而言的,immutable其实更多的是heap里面的不可变,String之所以这么设计,是因为String本身提供的方法已经很完备了,已经没有多态设计的空间了,所以final
  • 之所以有字符串常量池,是因为String在java中是不可变的。
  • 在Java程序中,有很多东西是永恒的,不会在运行过程中发生变化。比如一个类的名字、一个类

7、String 对象的加号“+”连接的内存表示

例1:

String str1 = new String("abc");
String str2 = "abc";
String str3 = "a" + "b" + "c";
System.out.println(str1.intern() == str2);   //输出true
System.out.println(str2 == str3);            //输出true

字符串常量是编译时候确定的,编译完成,生成class文件,那就不会再变了。

在定义str3的时候,在编译时候,编译器会将字符串常量直接放在一起,然后查找常量池里面,有没有对应的字符串。 所以str2 和 str3 是相等的,也就是指向相同的内存区域。

例2:

String str1 = "abc";
String str2 = "ab";
String str4 = str2 + "c";
System.out.println(str1 == str4);            //输出false

在定义str4的时候,是用str2+“c“的形式。这个时候str4的值不是编译时候能确定的,它已经不再会往常量池存放,是一个字符串变量。

这个时候,底层是通过StringBuffer的append方法,最终返回new的string。所以str4的地址只的不是常量池区域的地址,而是指向堆内存中的区域。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值