关于final,我们知道,它可以修饰类,方法,变量。
修饰类的时候:对象地址不可变。不可继承,也就不存在子类,类方法默认为final
修饰方法的时候:方法不可被重写。但可以继承
修饰变量的时候:变量不可重新赋值。
由jdk源码可得知,String类内部维护了一个私有的char数组以及一个int类型的hash值,很巧的是,这个数组也是由final修饰的。
private+final,防止我们修改这个char数组中的字符。
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
/** The value is used for character storage. */
private final char value[];
/** Cache the hash code for the string */
private int hash; // Default to 0
.....
就是因为它的这一不可变特性,java的常量池才得以实现,极大的节约堆内存空间(jdk8之后,常量池迁移到堆中了),所以同一个字符串对象,就会有多个引用,假如String可变,那么其他的引用对象数据也会跟着变
同时也理解为,它是一个线程安全的数据结构!因为重新赋值,它就是一个新的对象了,不影响原先的数据
再往下翻。发现构造器中会默认初始化字符串的哈希
/**
* Initializes a newly created {@code String} object so that it represents
* the same sequence of characters as the argument; in other words, the
* newly created string is a copy of the argument string. Unless an
* explicit copy of {@code original} is needed, use of this constructor is
* unnecessary since Strings are immutable.
*
* @param original
* A {@code String}
*/
public String(String original) {
this.value = original.value;
this.hash = original.hash;
}
这也是为什么Map类型的数据结构会使用String作为key!
再往下翻我们看到这里会调用本地方法intern,它的作用是将运行时的字符串放入常量池并返回
public native String intern();
如果不用final修饰String,那我重写这个方法,系统将会的不安全。
综上所诉,用final是很有必要的!!