为什么在java中实例变量有默认值?
为什么类中声明的变量有默认值,而方法中声明的变量(称为“局部变量”)在Java中没有默认值 比如说为什么在java中实例变量有默认值?,java,class,Java,Class,为什么类中声明的变量有默认值,而方法中声明的变量(称为“局部变量”)在Java中没有默认值 比如说 class abc { int a; public static void main(String ss[]) { int b; abc aa=new abc(); System.out.println(aa.a); System.out.println(b); } } 在上面的示例中,变
class abc
{
int a;
public static void main(String ss[])
{
int b;
abc aa=new abc();
System.out.println(aa.a);
System.out.println(b);
}
}
在上面的示例中,变量
a
的默认值为0,但变量b
给出的错误是它可能尚未初始化。局部变量初始化
在方法和块中声明的变量称为局部变量。局部变量在方法调用时创建时未初始化。因此,局部变量在使用之前必须显式初始化。否则,编译器将在执行包含方法或块时将其标记为错误
示例:
public class SomeClassName{
public static void main(String args[]){
int total;
System.out.println("The incremented total is " + total + 3); //(1)
}
}
编译器抱怨(1)处println语句中使用的局部变量total可能未初始化。
在使用前初始化局部变量total可解决此问题:
public class SomeClassName{
public static void main(String args[]){
int total = 45; //Local variable initialized with value 45 System.out.println("The incremented total is " + total+ 3); //(1)
}
}
字段初始化
如果实例或静态变量在声明时或在初始化程序块中未提供初始化,则它将使用其类型的默认值进行隐式初始化。
每次实例化类时,实例变量都会使用其类型的默认值初始化,即针对从该类创建的每个对象。
静态变量在第一次加载类时使用其类型的默认值初始化。所有成员变量都必须加载到堆中,以便在创建类实例时使用默认值初始化它们。对于局部变量,在Java7之前使用它们之前,它们不会加载到堆中,而是存储在堆栈中,所以我们需要显式地初始化它们。
现在,“Java热点服务器编译器”执行“转义分析”,并决定在堆栈上而不是堆上分配一些变量;博士:这或多或少是一个武断的选择 如果你问我,Java对实例变量有默认值是一个错误。编译器应该在编译之前强制程序员初始化它,就像局部变量的情况一样 默认值背后的基本原理是安全。当一个对象被实例化时,将为该对象分配一块内存,该对象包含实例变量所指向的位置等。Java设计人员决定用零和空擦除这部分内存是一个好主意。这样,您将永远不会读取在分配对象之前碰巧存在的垃圾。它们可以强制初始化;这个选择没有什么根本性的。它可能使事情易于实现,并且对Java的设计者来说有足够的意义
对于局部变量,设计人员选择强制初始化(或者更准确地说,当仅声明局部变量时,他们选择不进行任何类型的初始化,因此编译器最合乎逻辑的行为是在使用前强制初始化变量).当局部变量在堆栈上分配时,局部变量的内存块在赋值时分配 举个简单的例子
class Abc {
int i = -111;
int e;
int doSomething() {
int a = 10;
int b = a + i;
int c = b + 100;
Abc d = new Abc();
e = b + c + d.a;
return e + 1000;
}
}
以及javap-cbc
Compiled from "Abc.java"
class Abc {
int i;
int e;
Abc();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: aload_0
5: bipush -111
7: putfield #2 // Field i:I
10: return
int doSomething();
Code:
0: bipush 10
2: istore_1
3: iload_1
4: aload_0
5: getfield #2 // Field i:I
8: iadd
9: istore_2
10: iload_2
11: bipush 100
13: iadd
14: istore_3
15: new #3 // class Abc
18: dup
19: invokespecial #4 // Method "<init>":()V
22: astore 4
24: aload_0
25: iload_2
26: iload_3
27: iadd
28: aload 4
30: getfield #2 // Field i:I
33: iadd
34: putfield #5 // Field e:I
37: aload_0
38: getfield #5 // Field e:I
41: sipush 1000
44: iadd
45: ireturn
}
由于未为字段变量e
分配任何值,因此,如果原语为0,如果对象引用为null,则为0
如果你看doSomething()
对于要使用的局部变量,需要将初始值推入堆栈(在本例中为10)。如果没有此“推送”[初始化],后续语句将无法访问a的值(因为该值不在堆栈上)。一旦将该值推送到堆栈,其他操作(如iadd istore等)将在堆栈上执行
下面的语句实际上在堆空间上创建一个对象并调用init方法。这是未初始化变量(如“e”)获取默认值的地方
15: new #3 // class Abc
18: dup
我将进一步的字节码比较留给您;)但是我希望很清楚,
inta
实际上有一个默认值0
。对象的整个内存块总是用零填充,这就是为什么对象中的所有变量都默认为0,b
是一个局部变量,只是没有在该部分初始化。赋值时会初始化它,但y b变量没有默认值?b
是在堆栈中分配的,与a
不同,出于性能原因,它不会被置零。(或者更准确地说:不需要实现来清除它,因为它必然会限制实现的性能,从而获得很少的收益)请使用大写字母——我再也不会编辑您的文章了,但这个问题仍然没有答案。即使局部变量存储在堆栈上,为什么不给它们分配默认值呢?请参阅Java语言规范:Quote:“局部变量(§14.4,§14.14)在使用之前,必须通过初始化(§14.4)或赋值(§15.26)显式给定一个值,并且可以使用明确赋值的规则进行验证(§16)."@Ankur看最后一部分--Fields initializationLocal variables loaded to heap?你注意到OP谈论的是一个int,这是一个基元类型吗?o.OHe只是以int
为例。但是,如果你有一个local variable对象o
,引用仍然存在于堆栈中,而不是在堆中。如果你不初始化izeo
,使用它是一个错误——问题是在没有初始化的情况下使用引用。如果您只需执行o=null
,则可以使用它:您已经初始化了引用,引用仍然存在于堆栈中(不在堆中),并且没有任何内容“加载到堆中”在此初始化之后。如果执行o=new Object()
,则您已经触及了堆,但这与无法
int a = 10;
0: bipush 10
15: new #3 // class Abc
18: dup