为什么实例变量在java中有默认值?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/18226405/
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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 23:29:51  来源:igfitidea点击:

Why do instance variables have default values in java?

javaclass

提问by Shikhil Bhalla

Why do variables declared in a class have default values, but the variables declared inside methods, said to be "local variables", don't have default values in Java?

为什么在类中声明的变量有默认值,而在方法中声明的变量,称为“局部变量”,在Java中没有默认值?

For example

例如

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);
    }
 }

In this above example variable ahas default value of 0 but variable bgives error that it might not have been initialized.

在上面的示例中,变量的a默认值为 0,但变量b给出了它可能尚未初始化的错误。

采纳答案by Ashwani

All member variable have to load into heap so they have to initialized with default values when an instance of class is created. In case of local variables, they don't get loaded into heap they are stored in stack until they are being used before java 7, so we need to explicitly initialize them. Now the "Java Hotspot Server Compiler" performs "escape analysis" and decides to allocate some variables on the stack instead of the heap.

所有成员变量都必须加载到堆中,因此在创建类的实例时必须使用默认值进行初始化。在局部变量的情况下,它们不会被加载到堆中,它们存储在堆栈中,直到它们在 java 7 之前被使用,因此我们需要显式初始化它们。现在“Java Hotspot Server Compiler”执行“逃逸分析”并决定在堆栈而不是堆上分配一些变量。

回答by Dileep

Local variables Initialization

局部变量初始化

Variables declared in methods and in blocks are called local variables. Local variable are not initialized when they are created at method invocation. Therefore, a local variable must be initialized explicitly before being used. Otherwise the compiler will flag it as error when the containing method or block is executed.

在方法和块中声明的变量称为局部变量。局部变量在方法调用时创建时不会被初始化。因此,局部变量在使用前必须显式初始化。否则,当执行包含的方法或块时,编译器会将其标记为错误。

Example:

例子:

public class SomeClassName{

public static void main(String args[]){
int total;
System.out.println("The incremented total is " + total + 3); //(1)
}
}

The compiler complains that the local variable total used in println statement at (1) may not be initialized. Initializing the local variable total before usage solves the problem:

编译器抱怨在 (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)
}
}

Fields initialization

字段初始化

If no initialization is providedfor an instance or static variable, either when declared or in an initializer block, then it is implicitly initialized with the default value of its type. An instance variable is initialized with the default value of its type each time the class is instantiated, that is for every object created from the class. A static variable is initialized with the default value of its type when the class is first loaded.

如果在声明时或在初始化程序块中没有为实例或静态变量提供初始化,则使用其 type 的默认值隐式初始化。一个实例变量被初始化,其类型的每个类被实例化时间的缺省值,也就是对于从类创建的每个对象。静态变量在类首次加载时使用其类型的默认值进行初始化。

回答by Enno Shioji

tl;dr: It was more or less an arbitrary choice

tl;dr:这或多或少是一个任意的选择

If you ask me, it was a mistake that Java has default values for instance variables. The compiler should have forced the programmer to initialize it before like it is the case for local variables.

如果你问我,Java 有实例变量的默认值是错误的。编译器应该强制程序员在初始化它之前像局部变量的情况一样。

The rationale behind the default values is safety. When an object is instantiated, a chunk of memory will be allocated for the object which contains where the instance variables are pointing to etc. The Java designers decided it would be a good idea to wipe this part of memory with zeros and nulls. This way you will never read garbage that happened to be there before the object was allocated. They could have forced initialization; there is nothing fundamental about the choice. It probably made things easy to implement and made enough sense to the designers of Java.

默认值背后的基本原理是安全。当一个对象被实例化时,将为该对象分配一块内存,其中包含实例变量所指向的位置等。Java 设计者决定用零和空值擦除这部分内存是个好主意。这样,您将永远不会读取在分配对象之前碰巧存在的垃圾。他们可以强制初始化;选择没有什么基本的。它可能使事情更容易实现并且对 Java 的设计者来说足够有意义。

In case of local variables, the designers chose to force initialization (or perhaps it's more accurate to say they chose to not do any kind of initialization when a local variable is only declared, and thus the most logical behavior of the compiler was to force initialization of the variable before use).

在局部变量的情况下,设计者选择强制初始化(或者更准确地说,当只声明局部变量时,他们选择不进行任何类型的初始化,因此编译器最合乎逻辑的行为是强制初始化使用前的变量)。

回答by Prashant Bhate

As local variables are allocated on stack, memory chunk for a local variable is allocated when it is assigned with a value.

由于局部变量是在栈上分配的,局部变量的内存块是在给它赋值时分配的。

Take simple example

举个简单的例子

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;
    }
 }

and the bytecode from javap -c Abc

和字节码来自 javap -c Abc

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
}

When a method is inovked a memory space in the stack called current frameis allocated

当一个方法被调用时,堆栈中称为当前帧的内存空间被分配

If you look carefully even int a=-111;assignment happens in an implicit init function Abc()!

如果您仔细观察,即使int a=-111;赋值也会发生在隐式 init 函数中Abc()

       int a = -111;

       5: bipush        -111
       7: putfield      #2                  // Field a:I

As field variable eis not assigned any value it will be 0 if primitive or null if a Object reference

由于字段变量e未分配任何值,如果是原始值,则为 0,如果是对象引用,则为 null

And if you look at doSomething()

如果你看 doSomething()

        int a = 10;
        0: bipush        10

for a local to be used the initial value needs to be pushed into stack in this case 10 . without this 'push' [initialization] a's value is not accessible to subsequent statements (as the value is not on the stack). once the value is pushed to stack other operations like iadd istore etc are carried out on the stack

对于要使用的本地,在这种情况下需要将初始值推入堆栈 10 。没有这个“推”[初始化] a 的值不能被后续语句访问(因为该值不在堆栈上)。一旦将值推送到堆栈,其他操作(如 iadd istore 等)将在堆栈上执行

below statement actually creates an object on the heap space and invokes init method. This is where un initialized variables like 'e' gets default values

下面的语句实际上在堆空间上创建一个对象并调用 init 方法。这是像“e”这样的未初始化变量获得默认值的地方

      15: new           #3                  // class Abc
      18: dup

I leave further bytecode comparison upto you ;) but I hope it is clear

我将进一步的字节码比较留给您;) 但我希望它很清楚