java常见final类_java常见面试题分析之-字符串比较-延伸到final类型

文章内容包含:

关于字符串==比较的几种情况总结

关于final类型变量的初始化时机的总结

字符串==比较

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

分析总结:

1. 对于字符串常量的声明, 都会推送到字符串常量池中去缓存: 比如 String b = "niewj"; String c = "niewj"; 此时, 比较两个字符串reference(也就是比较他们指向的常量字符串的内存地址), 自然都是相同的缓存;

2. 对于声明的两个常量字符串 的 "+" 操作 String d = "niewj" + "hash"; 编译器也会做连接优化, 将其连接结果对应到字符串常量池中去比对缓存; 有则引用之; 所以此处的 a==d;

3. 字符串常量 和 非final字符串引用 的 "+", 编译器并不会提前优化, 而是需要计算得出, 并不会在 字符串常量池 中对应; 所以 a==e 为false;

4. 字符串String类的intern()方法的说明: 我们可以看到这样的说明: String s = "abc" (1)如果池中已经有了字符串s引用的字符串(根据equals方法比较:也就是比较字符串内容), 则直接返回池中的字符串引用; (2)如果池中没有, 那么intern会生成"abc"放入池中, 并返回此串引用; (3)如果两个字符串内容相同, s1.intern()==s2.intern()肯定是true;

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();

5. 关于final的字符串: final的字符串变量, 在声明时都会被放入到字符串常量池中; 不仅如此, 常量字符串和final类型字符串的 "+"操作也可以视为是 两个常量字符串的 "+" 操作, 也会到池中对取缓存; 为什么呢? final类型的变量, 只能初始化1次, 而且在使用的时候, 要求必须是已经初始化过了; 所以在 "+"操作的时候, 编译器已经能确认是有值了, 可以作为常量来对待, 因此作为常量字符串对待了;

6. 虽然也是final的字符串变量, 但是是通过调用方法获取的final值, 编译器无法在编译时预知, 所以不会进行优化, 所以在 "+"操作的时候, 编译器无法确定, 因此没有同步到池;

final类型变量的初始化时机

另外关于final变量初始化时机的总结:

final变量有3中:

(1) class中声明的实例final变量;

三种赋值时机:

直接赋值: 声明即赋值`class Const{ final int a=20; }

构造方法赋值: 声明时不赋值, 在构造方法中初始化赋值: class Const{ final int a; public Const(){a = 20;}}

实例块/初始化块赋值: 声明时不赋值,初始化块赋值:class Const{final int a; {a = 20;}}

(2) class中声明的static的final变量;

两种赋值时机:

直接赋值: 声明即赋值: class Const{static final int a = 20;}

静态块赋值: 声明时不赋值,静态块赋值: class Const{static final int a; static{a = 20;}}

(3) method中声明的final的变量;

一种:使用前初始化过即可; 特别注意的情景有一种,就是声明了不初始化, 也可以编译过: 因为没有使用:

public void test(){final int a;} 可以编译过, 因为后面没有对a变量的读取;

-->引申: 字符串常量池:关于字符串常量池的内存区域, 参见前面的整理: jvm字符串常量池在什么内存区域?

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值