Java中未初始化的变量和成员
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/268814/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Uninitialized variables and members in Java
提问by Yuval Adam
Consider this:
考虑一下:
public class TestClass {
private String a;
private String b;
public TestClass()
{
a = "initialized";
}
public void doSomething()
{
String c;
a.notify(); // This is fine
b.notify(); // This is fine - but will end in an exception
c.notify(); // "Local variable c may not have been initialised"
}
}
I don't get it. "b" is never initialized but will give the same run-time error as "c", which is a compile-time error. Why the difference between local variables and members?
我不明白。“b”永远不会被初始化,但会给出与“c”相同的运行时错误,这是一个编译时错误。为什么局部变量和成员有区别?
Edit: making the members private was my initial intention, and the question still stands...
编辑:将成员设为私有是我的初衷,问题仍然存在......
采纳答案by Tom Hawtin - tackline
The rules for definite assignment are quite difficult (read chapter 16 of JLS 3rd Ed). It's not practical to enforce definite assignment on fields. As it stands, it's even possible to observe final fields before they are initialised.
确定分配的规则非常困难(阅读 JLS 3rd Ed 的第 16 章)。在字段上强制执行明确的分配是不切实际的。就目前而言,甚至可以在初始化之前观察最终字段。
回答by user35094
The compiler can figure out that c will never be set. The b variable could be set by someone else after the constructor is called, but before doSomething(). Make b private and the compiler may be able to help.
编译器可以确定 c 永远不会被设置。b 变量可以在调用构造函数之后但在 doSomething() 之前由其他人设置。将 b 设为私有,编译器可能会有所帮助。
回答by Dave Costa
The compiler can tell from the code for doSomething() that c is declared there and never initialized. Because it is local, there is no possibility that it is initialized elsewhere.
编译器可以从 doSomething() 的代码中得知 c 是在那里声明的并且从未被初始化。因为是本地的,所以不可能在别处初始化。
It can't tell when or where you are going to call doSomething(). b is a public member. It is entirely possible that you would initialize it in other code before calling the method.
它无法告诉您何时何地调用 doSomething()。b 是公共成员。在调用该方法之前,您完全有可能在其他代码中对其进行初始化。
回答by jcoder
The language defines it this way.
语言以这种方式定义它。
Instance variables of object type default to being initialized to null. Local variables of object type are not initialized by default and it's a compile time error to access an undefined variable.
对象类型的实例变量默认初始化为空。默认情况下不会初始化对象类型的局部变量,访问未定义的变量是编译时错误。
See section 4.5.5 in here http://docs.oracle.com/javase/specs/jls/se7/html/jls-4.html#jls-4.12.5
请参阅此处http://docs.oracle.com/javase/specs/jls/se7/html/jls-4.html#jls-4.12.5 中的第 4.5.5 节
回答by Yuval
Here's the deal. When you call
这是交易。你打电话时
TestClass tc = new TestClass();
the new
command performs four important tasks:
该new
命令执行四项重要任务:
- Allocates memory on the heap for the new object.
- Initiates the class fields to their default values (numerics to 0, boolean to
false
, objects tonull
). - Calls the constructor (which may re-initiate the fields, or may not).
- Returns a reference to the new object.
- 在堆上为新对象分配内存。
- 将类字段初始化为其默认值(数字为 0,布尔值为
false
,对象为null
)。 - 调用构造函数(可能会重新启动字段,也可能不会)。
- 返回对新对象的引用。
So your fields 'a' and 'b' are both initiated to null
, and 'a' is re-initiated in the constructor. This process is not relevant for method calling, so local variable 'c' is neverinitialized.
因此,您的字段 'a' 和 'b' 都初始化为null
,并且在构造函数中重新初始化了 'a'。此过程与方法调用无关,因此永远不会初始化局部变量“c” 。
HTH
HTH
PS: for the gravely insomniac, read this.
PS:对于严重失眠的人,请阅读此内容。
回答by dpp
Member-variables are initialized to null or to their default primitive values, if they are primitives.
成员变量被初始化为 null 或它们的默认基元值,如果它们是基元的话。
Local variables are UNDEFINED and are not initialized and you are responsible for setting the initial value. The compiler prevents you from using them.
局部变量未定义且未初始化,您负责设置初始值。编译器会阻止您使用它们。
Therefore, b is initialized when the class TestClass is instantiated while c is undefined.
因此,当类 TestClass 被实例化而 c 未定义时, b 被初始化。
Note: null is different from undefined.
注意:null 与 undefined 不同。
回答by Bill K
You've actually identified one of the bigger holes in Java's system of generally attempting to find errors at edit/compile time rather than run time because--as the accepted answer said--it's difficult to tell if b is initialized or not.
您实际上已经确定了 Java 系统中的一个较大漏洞,即通常尝试在编辑/编译时而不是运行时查找错误,因为 - 正如公认的答案所说 - 很难判断 b 是否已初始化。
There are a few patterns to work around this flaw. First is "Final by default". If your members were final, you would have to fill them in with the constructor--and it would use path-analysis to ensure that every possible path fills in the finals (You could still assign it "Null" which would defeat the purpose but at least you would be forced to recognize that you were doing it intentionally).
有一些模式可以解决这个缺陷。首先是“默认为最终”。如果您的成员是最终成员,则必须使用构造函数填充它们 - 并且它将使用路径分析来确保每个可能的路径都填充最终结果(您仍然可以将其分配为“Null”,这会破坏目的,但是至少你会被迫承认你是故意这样做的)。
A second approach is strict null checking. You can turn it on in eclipse settings either by project or in default properties. I believe it would force you to null-check your b.notify() before you call it. This can quickly get out of hand so it tends to go with a set of annotations to make things simpler:
第二种方法是严格的空检查。您可以通过项目或默认属性在 eclipse 设置中打开它。我相信它会迫使您在调用之前对 b.notify() 进行空检查。这很快就会失控,因此它倾向于使用一组注释来使事情变得更简单:
The annotations might have different names but in concept once you turn on strict null checking and the annotations the types of variables are "nullable" and "NotNull". If you try to place a Nullable into a not-null variable you must check it for null first. Parameters and return types are also annotated so you don't have to check for null every single time you assign to a not-null variable.
注释可能有不同的名称,但在概念上,一旦您打开严格的空检查,并且注释的变量类型为“可空”和“NotNull”。如果您尝试将 Nullable 放入非空变量中,则必须首先检查它是否为空。参数和返回类型也有注释,因此您不必每次分配给非空变量时都检查空值。
There is also a "NotNullByDefault" package level annotation that will make the editor assume that no variable can ever have a null value unless you tag it Nullable.
还有一个“NotNullByDefault”包级别的注释,它将使编辑器假定任何变量都不能具有空值,除非您将其标记为 Nullable。
These annotations mostly apply at the editor level--You can turn them on within eclipse and probably other editors--which is why they aren't necessarily standardized. (At least last time I check, Java 8 might have some annotations I haven't found yet)
这些注释主要应用于编辑器级别——您可以在 eclipse 和其他编辑器中打开它们——这就是它们不一定标准化的原因。(至少我上次检查时,Java 8 可能有一些我还没有找到的注释)