作为 java 初学者记录一下, 有问题请多指教.
Why must local variables, including primitives, always be initialized in Java?
首先, 无论堆内还是栈中, 一块内存用完(即堆内成员不再被引用, 栈内方法出栈)后, 并不是说这块内容被清理干净(比如每一位都变为 0), 它的内容并没有变化, 只是被标记为可用状态.
那么, 如果声明一个成员变量或局部变量, 没有初始化(或赋值), 也没有默认值(成员变量有默认值, 这里假设没有), 就可能出现读取到尚未擦除的敏感数据, 带来安全问题. 所以, 解决这个问题就有两种方法:在声明时就给一个默认值, 这样就像成员变量一样;
在你读取内容之前, 就发现你没赋值, 提醒你有错, 强制你赋值, 就像局部变量一样.
那么为什么两个不一样呢? 我认为, 局部变量声明在方法中, 在方法内部, 局部变量的赋值和取值(读取)的顺序是确定的, 编译器是可以检查到读取局部变量之前你有没有给它赋值, 那么既然在编译器这里就能捕获错误, 那何乐而不为呢? 也就是说, 局部变量是可以具有默认值, 但如果编译器可以证明你正在尝试读取未初始化的变量, 就提前纠正你了, 那不更好吗? 所以与其为局部变量提供默认值, 更好的做法是强制你始终为其显式赋值。
但对于成员变量和静态变量来说, 编译器是无法知道调用方法的顺序的. 比如:
public class Test {
public String name;
public void dumpField() {
System.out.println("dumpField name=" + name);
}
}
name 的赋值可以发生在 dumpField() 之前, 也可以发生在 dumpField() 之后. 这是在运行时发生的, 在编译器来看确定不了的. 也就是说一个属性的 setter 和 getter 谁前谁后是不确定的, javac 也不知道, 所以就没办法提醒你是否可能产生错误和危险. 因此, java 就给了成员变量默认值(0, false, null等), 也就是说成员变量至少有一个已知值, 保证就算取值在赋值之前也能读取一个安全值, 这也就消除了读取尚未擦除的敏感数据的潜在安全问题.
References: