文章内容包含:java
import lombok.extern.slf4j.Slf4j; /** * @Author weijun.nie * @Date 2020/4/18 21:29 * @Version 1.0 */ @Slf4j public class StringDemo { public static void main(String[] args) { String hash = "hash"; final String hashFinal = "hash"; String b = "niewj"; String a = "niewjhash"; String c = "niewj"; String d = "niewj" + "hash"; String e = "niewj" + hash; String f = "niewj" + hashFinal; final String hashFinal2 = getByMethod(); String g = "niewj" + hashFinal2; log.info("字符串常量 比较: b==c -> {}", b == c); // true log.info("字符串常量 和 两个常量的+链接: a==d -> {}", a == d); // true log.info("字符串常量 和 一个常量链接一个变量: a==e -> {}", a == e); // false log.info("字符串常量 和 一个常量链接一个变量: a==e.intern() -> {}", a == e.intern()); // true log.info("字符串常量 和 一个常量链接一个final变量: a==f -> {}", a == f); // true log.info("字符串常量 和 一个常量链接一个调用方法获取的final变量: a==g -> {}", a == g); //false } private static String getByMethod() { return "hash"; } }
1[main]- 字符串常量 比较: b==c -> true 2[main]- 字符串常量 和 两个常量的+链接: a==d -> true 3[main]- 字符串常量 和 一个常量链接一个变量: a==e -> false 4[main]- 字符串常量 和 一个常量链接一个变量: a==e.intern() -> true 5[main]- 字符串常量 和 一个常量链接一个final变量: a==f -> true 6[main]- 字符串常量 和 一个常量链接一个调用方法获取的final变量: a==f -> false
分析总结:express
字符串常量池
中去缓存: 好比 String b = "niewj"; String c = "niewj";
此时, 比较两个字符串reference(也就是比较他们指向的常量字符串的内存地址), 天然都是相同的缓存;常量字符串
的 "+"
操做 String d = "niewj" + "hash";
编译器也会作链接优化, 将其链接结果对应到字符串常量池中去比对缓存; 有则引用之; 因此此处的 a==d;字符串常量
和 非final字符串引用
的 "+"
, 编译器并不会提早优化, 而是须要计算得出, 并不会在 字符串常量池
中对应; 因此 a==e 为false;Returns a canonical representation for the string object. A pool of strings, initially empty, is maintained privately by the class String. When the intern method is invoked, if the pool already contains a string equal to this String object as determined by the equals(Object) method, then the string from the pool is returned. Otherwise, this String object is added to the pool and a reference to this String object is returned. It follows that for any two strings s and t, s.intern() == t.intern() is true if and only if s.equals(t) is true. All literal strings and string-valued constant expressions are interned. String literals are defined in section 3.10.5 of the The Java™ Language Specification.
public native String intern();
segmentfault
final的字符串
: final的字符串变量, 在声明时都会被放入到字符串常量池中; 不只如此, 常量字符串和final类型字符串的 "+"
操做也能够视为是 两个常量字符串的 "+"
操做, 也会到池中对取缓存; 为何呢? final类型的变量, 只能初始化1次, 并且在使用的时候, 要求必须是已经初始化过了; 因此在 "+"
操做的时候, 编译器已经能确认是有值了, 能够做为常量来对待, 所以做为常量字符串对待了;调用方法获取的final值
, 编译器没法在编译时预知
, 因此不会进行优化, 因此在 "+"
操做的时候, 编译器没法肯定, 所以没有同步到池;另外关于final变量初始化时机的总结:
final变量有3中:缓存
三种赋值时机:jvm
直接赋值
: 声明即赋值`class Const{ final int a=20; }
构造方法赋值
: 声明时不赋值, 在构造方法中初始化赋值: class Const{ final int a; public Const(){a = 20;}}
实例块/初始化块赋值
: 声明时不赋值,初始化块赋值:class Const{final int a; {a = 20;}}
两种赋值时机:优化
直接赋值
: 声明即赋值: class Const{static final int a = 20;}
静态块赋值
: 声明时不赋值,静态块赋值: class Const{static final int a; static{a = 20;}}
一种:使用前
初始化过便可; 特别注意的情景有一种,就是声明
了不初始化
, 也能够编译
过: 由于没有使用:this
public void test(){final int a;}
能够编译过, 由于后面没有对a变量的读取;-->引伸: 字符串常量池
:关于字符串常量池的内存区域, 参见前面的整理: jvm字符串常量池在什么内存区域?code