【发布时间】:2010-02-02 20:55:09
【问题描述】:
对于这个 Java 代码:
String var;
clazz.doSomething(var);
为什么编译器会报这个错误:
变量 'var' 可能尚未初始化
我认为所有变量或引用都初始化为null。为什么需要这样做:
String var = null;
??
【问题讨论】:
标签: java initialization
对于这个 Java 代码:
String var;
clazz.doSomething(var);
为什么编译器会报这个错误:
变量 'var' 可能尚未初始化
我认为所有变量或引用都初始化为null。为什么需要这样做:
String var = null;
??
【问题讨论】:
标签: java initialization
【讨论】:
null?
这是因为 Java 非常有用(尽可能)。
它将使用相同的逻辑来捕捉您可能错过的一些非常有趣的边缘情况。例如:
int x;
if(cond2)
x=2;
else if(cond3)
x=3;
System.out.println("X was:"+x);
这将失败,因为存在未指定的 else 情况。事实是,这里绝对应该指定一个 else 情况,即使它只是一个错误(默认情况也是如此:switch 语句中的条件)。
有趣的是,您应该从中得到的好处是,在您确定确实必须这样做之前,永远不要初始化您的局部变量。如果你习惯总是说“int x=0;”您将阻止这个奇妙的“错误逻辑”检测器运行。这个错误不止一次为我节省了时间。
【讨论】:
Bill K 同上。我补充说:
Java 编译器可以保护您免受在函数中使用变量之前未能设置变量的伤害。因此,它没有像 Bill K 所描述的那样明确设置默认值。
但是当涉及到类变量时,编译器很难为你做这件事。类变量可以由类中的任何函数设置。编译器很难确定调用函数的所有可能顺序。至少它必须分析系统中调用此类中任何函数的所有类。它可能必须检查任何数据文件或数据库的内容,并以某种方式预测用户将输入什么内容。最好的情况是任务极其复杂,最坏的情况是不可能的。所以对于类变量,提供一个可靠的默认值是有意义的。该默认值基本上是用零位填充字段,因此引用为 null,整数为 0,布尔值为 false,等等。
正如比尔所说,你绝对不应该养成在声明变量时自动初始化变量的习惯。如果这在您的程序上下文中确实有意义,则仅在声明时初始化变量。比如,如果 99% 的时间你希望 x 为 42,但在某些 IF 条件下,你可能会发现这是一个特殊情况,x 应该是 666,那么很好,从“int x=42;”开始并在 IF 内部覆盖它。但在更正常的情况下,根据任何条件计算出值,不要初始化为任意数字。只需用计算值填充它。然后,如果您在某些条件组合下出现逻辑错误并且无法设置值,编译器会告诉您是您搞砸了而不是用户搞砸了。
PS 我见过很多蹩脚的程序,它们会说:
HashMap myMap=new HashMap();
myMap=getBunchOfData();
当你知道一毫秒后你会立即扔掉这个对象时,为什么还要创建一个对象来初始化变量呢?那只是浪费时间。
编辑
举个简单的例子,假设你是这样写的:
int foo;
if (bar<0)
foo=1;
else if (bar>0)
foo=2;
processSomething(foo);
这会在编译时抛出错误,因为编译器会注意到当 bar==0 时,您从未设置 foo,但随后您尝试使用它。
但是如果你将 foo 初始化为一个虚拟值,比如
int foo=0;
if (bar<0)
foo=1;
else if (bar>0)
foo=2;
processSomething(foo);
然后编译器将看到无论 bar 的值是什么,foo 都被设置为某个值,因此它不会产生错误。如果您真正想要的是当 bar 为 0 时 foo 为 0,那么这很好。但是,如果真正发生的事情是您的意思是其中一个测试是 =,或者您的意思是在 bar==0 时包含一个最终的 else,那么您已经欺骗了编译器,使其无法检测到您的错误。顺便说一句,我认为这样的构造是糟糕的编码风格:不仅编译器无法确定您的意图,而且未来的维护程序员也无法确定。
【讨论】:
我喜欢 Bill K 关于让编译器为你工作的观点——我陷入了对每个自动变量的初始化,因为它“看起来像是 Java 要做的事情”。我无法理解类变量(即构造函数担心的持久性事物)和自动变量(一些计数器等)是不同的,即使一切都是 Java 中的类。
所以我返回并删除了我将要使用的初始化,例如
List <Thing> somethings = new List<Thing>();
somethings.add(somethingElse); // <--- this is completely unnecessary
很好。我收到了编译器警告
List<Thing> somethings = new List();
我认为问题在于缺乏初始化。错误的。问题是我没有理解规则,我需要在“新”中标识的<Thing>,而不是创建的任何<Thing> 类型的实际项目。
(接下来我需要学习如何将文字小于和大于符号放入 HTML!)
【讨论】:
我不知道它背后的逻辑,但是局部变量没有初始化为null。我想让你的生活变得轻松。如果可能的话,他们本可以使用类变量来完成。这并不意味着您必须在一开始就对其进行初始化。这很好:
MyClass cls;
if (condition) {
cls = something;
else
cls = something_else;
【讨论】:
当然,如果您在显示时确实有两行重叠 - 声明它,填充它,不需要默认构造函数。但是,例如,如果您想声明一次并多次使用它,则默认构造函数或 null 声明是相关的。或者指向对象的指针是否如此轻量级以至于最好在循环内一遍又一遍地分配它,因为指针的分配比对象的实例化少得多? (大概在循环的每一步都有一个新对象的正当理由)。
第四号法案
【讨论】: