天天看点

java.lang.String--字符串字面量

String类的源码介绍

All string literals in Java programs, such as "abc", are implemented as instances of this class. 

java中的所有字符串字面量都是String类的实例

For example: String str = "abc";

字符串字面量可以直接调用字符串类的方法,如下所示

System.out.println("rfdf".length());

字符串常量池

是一用来保存字符串对象引用的容器。并且其中的内容不会重复。

即使字符串是不可变的,它仍然和Java中的其他对象一样。对象都是创建在堆中,字符串也不例外。

所以字符串常量池仍然依靠堆,他们存储的只是堆中字符串的引用。

在JDK6.0及之前版本,字符串常量池存放在方法区中在JDK7.0版本以后,字符串常量池被移到了堆中了。在HotSpot VM里实现string pool功能的是一个StringTable类,它是一个Hash表,默认值大小长度是1009;这个StringTable在每个HotSpot VM的实例只有一份,被所有的类共享。

字符串字面量是怎么加载到常量池中的

1、当一个.java文件被编译成.class文件时,和所有其他常量一样,每个字符串字面量都通过一种特殊的方式被记录下来。

2、当一个.class文件被加载时(注意加载发生在初始化之前),JVM在.class文件中寻找字符串字面量。

3、当找到一个时,JVM会检查是否有相等的字符串在常量池中存放了堆中引用。

如果找不到,就会在堆中创建一个对象,然后将它的引用存放在池中的一个常量表中。

4、一旦一个字符串对象的引用在常量池中被创建,这个字符串在程序中的所有字面量引用都会被常量池中已经存在的那个引用代替。

涉及字面量的一些问题

1、如果只是字面量进行拼接如下所示

String c="3"+"45";

JVM会将它们优化成一个字面量即class文件反编译后的代码如下所示

String c = "1223";

2、字符串创建的两种方式以及区别

String a="345";

字面量"345"会首先去字符串常量池找是否有"345"这个字符串,如果有直接返回引用,如果没有则在堆中创建一个新对象并把该对象的引用存储在常量池中并返回该引用。

只创建了一个对象

String b=new String("345");

在类加载时,首先判断字符串常量池中是否存在"345"对象的引用,没有则创建一个"345"对象,然后把这个对象的引用存放在字符串常量池中。

new关键字会在堆中创建一个新的对象。

b是在堆中的引用,而不是常量池中的。

故创建了一个(常量池中有)或者两个对象(常量池中无)

3、如果拼接中存在字符串变量,JVM会将它们优化成StringBuilder进行拼接,然后通过StringBuilder.toString()获取。

而StringBuilder.toString()是用new String的方式来获取字符串,这种的会返回堆中的字符串对象,而不是常量池中的对象。

public String toString() {
        // Create a copy, don't share the array
        return new String(value, 0, count);
    }
           

String a="345";

String f="3";

String h=f+"45";

System.out.println(a==h);

结果为false

4、String的intern()方法

String的intern()方法是一个本地方法,定义为public native String intern(); intern()方法的价值在于让开发者能将注意力集中到String池上。当调用 intern 方法时,如果池已经包含一个等于此 String 对象的字符串(该对象由 equals(Object) 方法确定),则返回池中的字符串。否则,将此 String 对象添加到池中,并且返回此 String 对象在常量池中的引用。例如:下面的代码运行结果为true。

String str1 = new String("abc").intern();

String str2 = "abc";

System.out.println(str1 == str2);

5、为什么不要在循环中去拼接字符串

因为字符串拼接在编译时期JVM会将其优化成StringBuilder对象进行拼接,如果循环次数非常大的话,创建的StringBuilder对象非常的多,甚至可能会导致内存溢出的情况。

垃圾回收

字符串字面量不会被垃圾回收。

原因

字面量存储在堆中,但是在字符串常量池中一直会存在这个对象的引用。

字符串字面量总是有一个来自字符串常量池的引用。

Java面试题:java字符串字面量

Java中的字符串字面量

深入了解Java字符串常量池