关于String的特性介绍

前言:

写这篇博客是因为本人已经大三了,不想考研,要忙着找实习工作了。
在做一些相关的java复习题时,发现自己对一些java里面的特性不是很清楚,通过博客记录题目的同时深挖一些相关的特性。
话不多说,进入正题。

上题:

class TestString {

    public static void main(String[] args) {
        String s1 = "Programming";
        String s2 = new String("Programming");
        String s3 = "Program";
        String s4 = "ming";
        String s5 = "Program" + "ming";
        String s6 = s3 + s4;
        System.out.println(s1 == s2);
        System.out.println(s1 == s5);
        System.out.println(s1 == s6);
        System.out.println(s1 == s6.intern());
        System.out.println(s2 == s2.intern());
    }
}

需要我们来分析这些代码的运行结果。

这是运行结果:
false
true
false
true
false
本题主要考察String的内存分配。
在此引入常量池,栈,堆这几个概念:
常量池(constant pool):指的是在编译期被确定,并被保存在已编译的.class文件中的一些数据。它包括了关于类、方法、接口等中的常量,也包括字符串常量
:栈主要存放在运行期间用到的一些局部变量(基本数据类型的变量)或者是指向其他对象的一些引用,因为方法执行时,被分配的内存就在栈中,所以当然存储的局部变量就在栈中咯。当一段代码或者一个方法调用完毕后,栈中为这段代码所提供的基本数据类型或者对象的引用立即被释放;
:当你需要创建一个对象的时候,只需要new写一行简单的代码,当执行 这行代码时,会自动在堆里进行存储分配。

首先,我们要知道Java会确保一个字符串常量在常量池只有一份存在。

String s1 = “Programming”;这句在因为“Programming”是常量,先在常量池查找,是否存在该常量,
若无则创建,有则返回该常量的引用给s1,

用new String() 创建的字符串不是常量,不能在编译期就确定,所以new String() 创建的字符串不放入常量池中,而是放入堆中,它们有自己的地址空间。

所以有s1==s2,比较地址,返回false;

对于 String s5 = “Program” + “ming”; 这句代码编译器会自动把 “Program” + "ming"优化成“Programming”,所以有s1==s5。
扩展: 对于“p”+“ro”+"garaming"编译器就无法优化,会使用StringBuilder.append(),最后还是会在堆上创建新对象

String s6 = s3 + s4;这种使用StringBuilder.append()创建新对象。所以s1==s6返回false。

String的intern()方法就是扩充常量池的一个 方法;当一个String实例str调用intern()方法时,Java查找常量池中是否有相同Unicode的字符串常量,如果有,则返回其的引用, 如果没有,则在常量池中增加一个Unicode等于str的字符串并返回它的引用;
所以有最后的运行结果。