Java Final 变量有默认值吗?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/24990691/
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
Will Java Final variables have default values?
提问by user3766874
I have a program like this:
我有一个这样的程序:
class Test {
final int x;
{
printX();
}
Test() {
System.out.println("const called");
}
void printX() {
System.out.println("Here x is " + x);
}
public static void main(String[] args) {
Test t = new Test();
}
}
If I try to execute it, i am getting compiler error as : variable x might not have been initialized
based on java default values i should get the below output right??
如果我尝试执行它,我会收到编译器错误:variable x might not have been initialized
基于 java 默认值,我应该得到以下输出,对吗?
"Here x is 0".
Will final variables have dafault values?
最终变量会有默认值吗?
if I change my code like this,
如果我像这样改变我的代码,
class Test {
final int x;
{
printX();
x = 7;
printX();
}
Test() {
System.out.println("const called");
}
void printX() {
System.out.println("Here x is " + x);
}
public static void main(String[] args) {
Test t = new Test();
}
}
I am getting output as:
我得到的输出为:
Here x is 0
Here x is 7
const called
Can anyone please explain this behavior..
任何人都可以解释这种行为..
回答by sp00m
http://docs.oracle.com/javase/tutorial/java/javaOO/initial.html, chapter "Initializing Instance Members":
http://docs.oracle.com/javase/tutorial/java/javaOO/initial.html,“初始化实例成员”一章:
The Java compiler copies initializer blocks into every constructor.
Java 编译器将初始化块复制到每个构造函数中。
That is to say:
也就是说:
{
printX();
}
Test() {
System.out.println("const called");
}
behaves exactly like:
行为完全像:
Test() {
printX();
System.out.println("const called");
}
As you can thus see, once an instance has been created, the final field has not been definitely assigned, while (from http://docs.oracle.com/javase/specs/jls/se7/html/jls-8.html#jls-8.3.1.2):
正如您所看到的,一旦创建了一个实例,最后一个字段还没有被明确分配,而(来自http://docs.oracle.com/javase/specs/jls/se7/html/jls-8.html #jls-8.3.1.2):
A blank final instance variable must be definitely assigned at the end of every constructor of the class in which it is declared; otherwise a compile-time error occurs.
必须在声明它的类的每个构造函数的末尾明确分配一个空白的最终实例变量;否则会发生编译时错误。
While it does not seem to be stated explitely in the docs (at least I have not been able to find it), a final field must temporary take its default value before the end of the constructor, so that it has a predictable valueif you read it before its assignment.
虽然它似乎没有在文档中明确说明(至少我找不到它),但最终字段必须在构造函数结束之前临时采用其默认值,以便它具有可预测的值,如果你在分配之前阅读它。
Default values: 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
On your second snippet, x is initialized on instance creation, so the compiler does not complain:
在您的第二个代码段中, x 在实例创建时初始化,因此编译器不会抱怨:
Test() {
printX();
x = 7;
printX();
System.out.println("const called");
}
Also note that the following approach doesn't work. Using default value of final variable is only allowed through a method.
另请注意,以下方法不起作用。仅允许通过方法使用最终变量的默认值。
Test() {
System.out.println("Here x is " + x); // Compile time error : variable 'x' might not be initialized
x = 7;
System.out.println("Here x is " + x);
System.out.println("const called");
}
回答by Michael D.
As far as I'm aware, the compiler will always initialize class variables to default values (even final variables). For example, if you were to initialize an int to itself, the int would be set to its default of 0. See below:
据我所知,编译器总是将类变量初始化为默认值(甚至是最终变量)。例如,如果您要将一个 int 初始化为自身,则该 int 将设置为其默认值 0。见下文:
class Test {
final int x;
{
printX();
x = this.x;
printX();
}
Test() {
System.out.println("const called");
}
void printX() {
System.out.println("Here x is " + x);
}
public static void main(String[] args) {
Test t = new Test();
}
}
The above would print the following:
以上将打印以下内容:
Here x is 0
Here x is 0
const called
回答by alfasin
If you don't initialize x
you'll get a compile-time error since x
is never initialized.
如果你不初始化,x
你会得到一个编译时错误,因为x
它从未被初始化。
Declaring x
as final means that it can be initialized only in the constructor or in initializer-block(since this block will be copied by the compiler into every constructor).
声明x
为 final 意味着它只能在构造函数或初始化块中初始化(因为这个块将被编译器复制到每个构造函数中)。
The reason that you get 0
printed out before the variable is initialized is due to the behavior defined in the manual(see: "Default Values" section):
0
在变量初始化之前打印出来的原因是由于手册中定义的行为(请参阅:“默认值”部分):
Default Values
默认值
It's not always necessary to assign a value when a field is declared. Fields that are declared but not initialized will be set to a reasonable default by the compiler. Generally speaking, this default will be zero or null, depending on the data type. Relying on such default values, however, is generally considered bad programming style.
The following chart summarizes the default values for the above data types.
声明字段时并不总是需要赋值。已声明但未初始化的字段将由编译器设置为合理的默认值。一般而言,此默认值将为零或空值,具体取决于数据类型。然而,依赖这样的默认值通常被认为是糟糕的编程风格。
下图总结了上述数据类型的默认值。
Data Type Default Value (for fields)
--------------------------------------
byte 0
short 0
int 0
long 0L
float 0.0f
double 0.0d
char '\u0000'
String (or any object) null
boolean false
回答by Martin Andersson
All non-final fields of a class initialize to a default value (0
for nummeric data types, false
for boolean and null
for reference types, sometimes called complex objects). These fields initialize before a constructor (or instance initialization block) executes independent of whether or not the fields was declared before or after the constructor.
类的所有非最终字段都初始化为默认值(0
对于数字数据类型、false
布尔值和null
引用类型,有时称为复杂对象)。这些字段在构造函数(或实例初始化块)执行之前初始化,与这些字段是在构造函数之前还是之后声明无关。
Finalfields of a class has no default valueand must be explicitly initialized just once before a class constructor has finished his job.
类的最终字段没有默认值,并且必须在类构造函数完成其工作之前显式初始化一次。
Local variables on the inside of an execution block (for example, a method) has no default value. These fields must be explicitly initialized before their first use and it doesn't matter whether or not the local variable is marked as final.
执行块(例如,方法)内部的局部变量没有默认值。这些字段在第一次使用之前必须显式初始化,并且局部变量是否标记为 final 无关紧要。
回答by udalmik
JLSis sayingthat you mustassign the default value to blank final instance variable in constructor (or in initialization blockwhich is pretty the same). That is why you get the error in the first case. However it doesn't say that you can not access it in constructor before. Looks weird a little bit, but you can access it before assignment and see default value for int - 0.
JLS是说,你必须在构造函数中的默认值赋给空白最终实例变量(或初始化块,这是非常相同)。这就是为什么在第一种情况下会出现错误的原因。但是,它并不是说您之前不能在构造函数中访问它。看起来有点奇怪,但是您可以在赋值之前访问它并查看 int - 0 的默认值。
UPD.As mentioned by @I4mpi, JLSdefinesthe rule that each value should be definitely assignedbefore any access:
更新。正如@I4mpi 所提到的,JLS定义了在任何访问之前都应该明确分配每个值的规则:
Each local variable (§14.4) and every blank final field (§4.12.4, §8.3.1.2) must have a definitely assigned value when any access of its value occurs.
Each local variable (§14.4) and every blank final field (§4.12.4, §8.3.1.2) must have a definitely assigned value when any access of its value occurs.
However, it also has an interesting rulein regards to constructors and fields:
然而,它在构造函数和字段方面也有一个有趣的规则:
If C has at least one instance initializer or instance variable initializer then V is [un]assigned after an explicit or implicit superclass constructor invocation if V is [un]assigned after the rightmost instance initializer or instance variable initializer of C.
If C has at least one instance initializer or instance variable initializer then V is [un]assigned after an explicit or implicit superclass constructor invocation if V is [un]assigned after the rightmost instance initializer or instance variable initializer of C.
So in second case the value x
is definitely assignedat the beginning of the constructor, because it contains the assignment at the end of it.
因此,在第二种情况下,价值x
被明确赋值在构造函数的开头,因为它包含在它的最终分配。
回答by dharam
Let me put it in the simplest words I can.
让我用我能用的最简单的话来说吧。
final
variables need to be initialized, this is mandated by the Language Specification.
Having said that, please note that it is not necessary to initialize it at the time of declaration.
final
变量需要初始化,这是语言规范规定的。话虽如此,请注意,在声明时不必对其进行初始化。
It is required to initialize that before the object is initialized.
需要在初始化对象之前进行初始化。
We can use initializer blocks to initialize the final variables. Now, initializer blocks are of two types
static
and non-static
我们可以使用初始化块来初始化最终变量。现在,初始化块有两种类型
static
,non-static
The block you used is a non-static initializer block. So, when you create an object, Runtime will invoke constructor and which in turn will invoke the constructor of the parent class.
您使用的块是非静态初始化块。因此,当您创建一个对象时,Runtime 将调用构造函数,而后者又将调用父类的构造函数。
After that, it will invoke all the initializers (in your case the non-static initializer).
之后,它将调用所有初始化程序(在您的情况下为非静态初始化程序)。
In your question, case 1: Even after the completion of initializer block the final variable remains un-initialized, which is an error compiler will detect.
在您的问题中,案例 1:即使在初始化程序块完成后,最终变量仍然未初始化,这是编译器将检测到的错误。
In case 2: The initializer will initialize the final variable, hence the compiler knows that before the object is initialized, the final is already initialized. Hence, it will not complain.
在情况 2 中:初始化器将初始化 final 变量,因此编译器知道在初始化对象之前,final 已经初始化。因此,它不会抱怨。
Now the question is, why does x
takes a zero. The reason here is that compiler already knows that there is no error and so upon invocation of init method all the finals will be initialized to defaults, and a flag set that they can change upon actual assignment statement similar to x=7
.
See the init invocation below:
现在的问题是,为什么不x
取零。这里的原因是编译器已经知道没有错误,因此在调用 init 方法时,所有 finals 都将被初始化为默认值,并设置一个标志集,它们可以在类似于x=7
. 请参阅下面的 init 调用:
回答by Bohemian
The first error is the compiler complaining that you have a final field, but no code to initialize it - simple enough.
第一个错误是编译器抱怨你有一个 final 字段,但没有初始化它的代码 - 很简单。
In the second example, you have code to assign it a value, but the sequence of execution means you reference the field both before and after assigning it.
在第二个示例中,您有代码为其分配一个值,但执行顺序意味着您在分配之前和之后都引用了该字段。
The pre-assigned value of any field is the default value.
任何字段的预分配值都是默认值。
回答by async
If I try to execute it, i am getting compiler error as : variable x might not have been initialized based on java default values i should get the below output right??
"Here x is 0".
如果我尝试执行它,我会收到编译器错误,因为:变量 x 可能尚未根据 Java 默认值进行初始化,我应该得到以下输出,对吗?
“这里 x 是 0”。
No. You are not seeing that output because you are getting a compile-time error in the first place. Final variables do get a default value, but the Java Language Specification (JLS) requires you to initialize them by the end of the constructor (LE: I'm including initialization blocks here), otherwise you'll get a compile-time error which will prevent your code to be compiled and executed.
不。您没有看到该输出,因为您首先遇到了编译时错误。最终变量确实有一个默认值,但 Java 语言规范 (JLS) 要求您在构造函数的末尾初始化它们(LE:我在这里包括了初始化块),否则您会得到一个编译时错误将阻止您的代码被编译和执行。
Your second example respects the requirement, that's why (1) your code compiles and (2) you get the expected behaviour.
你的第二个例子尊重要求,这就是为什么(1)你的代码编译和(2)你得到预期的行为。
In the future try to familiarize yourself with the JLS. There's no better source of information about the Java language.
将来尝试熟悉 JLS。没有比 Java 语言更好的信息来源了。