2013-08-14 8 views
20

クラス内で宣言された変数にはデフォルト値がありますが、メソッド内で宣言された変数(ローカル変数)はJavaでデフォルト値を持たないのはなぜですか?この上記の例では、例えばインスタンス変数が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); 
    } 
} 

が変数aは、デフォルト値の0を持っていますが、変数bは、それが初期化されていない可能性があることエラーが発生します。

+14

'int型A'実際に明確である' 0のデフォルト値を持っている願っています'。 – Vulcan

+1

オブジェクトのメモリブロック全体が常に0で埋められます。つまり、オブジェクトのすべての変数がデフォルトで0になるのはなぜですか?bはローカル変数であり、単純にその部分では初期化されません。値が – x4rf41

+1

に割り当てられたときに初期化されますが、y b変数にはデフォルト値がありませんか? –

答えて

12

すべてのメンバ変数は、クラスのインスタンスが作成されるときにデフォルト値で初期化する必要があるように、ヒープにロードする必要があります。ローカル変数の場合、それらはヒープにロードされず、Java 7より前に使用されるまでスタックに格納されるため、明示的に初期化する必要があります。 "Java Hotspot Server Compiler"は "エスケープ解析"を実行し、ヒープの代わりにスタックにいくつかの変数を割り当てることを決めました。

+0

ローカル変数がヒープにロードされていますか?あなたはOPがint *について話しているのに気付きましたか?これはプリミティブ型ですか? o.O –

+0

彼は一例として 'int'を取っています。 – Ashwani

+0

しかし、ローカル変数 'Object o'を持っていれば、* reference *はヒープではなくスタックに残ります。 'o'を初期化しなければ、それを使うのはエラーです - 初期化せずに* reference *を使うのが問題です。単純に 'o = null'を実行すれば、それを使うことができます。リファレンスを初期化しました。これはスタック内にあり(ヒープではなく)、この初期化の後に"ヒープにロードされた "ものはありません。 'o = new Object()'を実行すると、ヒープに触れましたが、これだけで初期化されていないローカル変数を使用することはできません。 –

2

ローカル変数の初期化方法にして、ブロック内で宣言

変数はローカル変数と呼ばれています。ローカル変数は、メソッド呼び出し時に作成されたときには初期化されません。したがって、ローカル変数は使用する前に明示的に初期化する必要があります。さもなければ、コンパイラは、それが含まれているメソッドまたはブロックが実行されたときにそれをエラーとしてフラグを立てます。

例:

public class SomeClassName{ 

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

コンパイラは、(1)でのprintlnステートメントに使用されるローカル変数の合計が初期化されないことを訴えます。 使用が問題を解決する前に、ローカル変数の合計を初期化:

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

フィールドの初期化

ない初期化をインスタンスまたは静的変数のが提供されていない場合、いずれかの宣言又は初期化子ブロック内の場合、 は、暗黙的にそのタイプのデフォルト値であるで初期化されます。 インスタンス変数は、クラスがインスタンス化されるたびに、そのタイプのデフォルト値であるで初期化されます。つまり、クラスから作成されたすべてのオブジェクトです。 静的変数は、クラスが最初にロードされるときにその型のデフォルト値で初期化されます。

+2

しかし、依然として問題は解決されていません。ローカル変数がスタックに格納されていても、なぜそれらにはデフォルト値が割り当てられません。 –

+2

Java言語仕様を参照してください。http://docs.oracle.com/javase/specs/jls/se7/html/jls-4.html#jls-4.12.5引用:「ローカル変数(14.4、§14.14) (§14.4)または割り当て(§15.26)のいずれかによって明示的に値を与えなければなりません。これは明確な割り当て規則(§16)を使って検証することができます。 –

+0

@Ankur最後の部分を見てください---フィールドの初期化 – Dileep

0

TL; DR:あなたは私に言わせればそれは多かれ少なかれ、任意の選択

だった、それはJavaがインスタンス変数のデフォルト値を持っていることを間違いでした。コンパイラは、ローカル変数の場合と同じように、プログラマに初期化を強制する必要がありました。

デフォルト値の背後にある論理的根拠は安全です。オブジェクトがインスタンス化されると、インスタンス変数が指し示す場所を含むオブジェクトにメモリのチャンクが割り当てられます。Javaデザイナーは、メモリのこの部分をゼロとヌルでワイプすることをお勧めします。この方法では、オブジェクトが割り当てられる前にそこにあったゴミを決して読み取ることはありません。強制的に初期化される可能性があります。その選択について根本的なものは何もない。おそらく、Javaの設計者にとっては、実装が容易で、十分な意味がありました。

ローカル変数の場合、デザイナーは強制的に初期化を選択しました(または、ローカル変数が宣言されているときのみ初期化を行わないことを選択した方が正確かもしれないため、コンパイラの最も論理的な動作使用前に変数の初期化を強制することでした)。

+0

インスタンスメンバーが割り当て前に使用されたことをコンパイラが知ることは不可能です。コンパイラは、クラスのどのメソッドが最初に呼び出されるかを知らない。一方で、エントリーポイントが1つしかないので、同じ方法の分析が可能です。 – EJP

+0

@EJP Kotlinはかなり良い仕事をしているようだ... –

+0

Javaはそれほどスマートである必要はありません。 – weakish

1

ローカル変数はスタックに割り当てられるため、ローカル変数のメモリチャンクには値が割り当てられて割り当てられます。この方法は、あなたの場合は、現在のフレームが

を割り当てられていると呼ばれるスタック内のメモリ空間をinovkedされている場合

は簡単な例

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

からバイトコードを取ります慎重に見てくださいint a=-111;暗黙のinit関数で割り当てが発生しますAbc()!フィールド変数eは、任意の値を割り当てられないように、オブジェクト参照が

そして、あなたは地元のためにdoSomething()

 int a = 10; 
     0: bipush  10 

を見ればする場合

 int a = -111; 

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

は、それが0であれば、プリミティブまたはnullになりますこの場合、初期値をスタックにプッシュする必要があります。この 'push' [initialization] aの値は、後続のステートメントにはアクセスできません(値はスタック上にないため)。値がプッシュされてiadd istoreなどの他の操作がスタック上で実行されると、

以下のステートメントは実際にヒープスペース上にオブジェクトを作成し、initメソッドを呼び出します。 「E」のように、未初期化された変数は、私はあなた件までさらにバイトコードの比較を残す

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

デフォルト値を取得する場所です;)私はそれが

+0

あなたの心を作りましょう。ローカル変数の 'メモリチャンク'は、メソッドが入力されたときに割り当てられる値 '*または*が割り当てられたときに割り当てられます。同時に両方ではありません。 'ipush'ステートメントは、直後の 'istore'命令ストアが 'a'のスタックスロットに格納する値10をプッシュします。プッシュは「a」を作成しません。 – EJP

関連する問題