【Javaちゃんぽん】静的変数、インスタンス変数、ローカル変数、final修飾変数のデフォルト初期値の問題

20471 ワード

静的変数、インスタンス変数、ローカル変数、final修飾変数のデフォルト初期値の問題
質問:
(1)ここでは,メンバー変数とローカル変数のデフォルト初期値について検討するが,メンバー変数とローカル変数が宣言された後に初期化付与操作を行わず,次のコードでそれらを使用し,たとえば出力すると,どのような問題が発生するかを調べる.(2)メンバー変数がfinalキーワードで修飾され、明示的に値を初期化せずに宣言される場合、JVMはメンバー変数の暗黙的な初期化を支援しますか?
前提:問題を解決する前に、メンバー変数とは何かを明確にします.ローカル変数とは?
  • メンバー変数は、静的変数(クラス変数)とインスタンス変数に分けられる.
  • 静的変数はクラス内でメソッド以外にstaticキーワードで修飾された変数である.
  • インスタンス変数はオブジェクトの変数であり、クラスではメソッド以外の一般メンバー変数である.

  • 局所変数がメソッド内の変数である.
  • ローカル変数は、パラメータ、メソッドローカル変数、コードブロックローカル変数を含み、メソッドのパラメータリスト、メソッド内およびコードブロック(静的コードブロックを含む)に存在し、メソッドの範疇に属する.


  • これらの概念を理解した上で,以下のコードを見ることができる.
    テスト1
    メンバー変数とローカル変数をそれぞれ初期化せずに宣言するテスト
    コード(一):メンバー変数テスト
    public class MemberVar {
    
    	//            ,JVM                 
    	static int sI;
    	static Integer sInteger;
    	static char sC;
    	static String sString;
    	static boolean sB;
    	static Boolean sBoolean;
    	//             ,JVM                  
    	int oInt;
    	char oChar;
    
    	public static void main(String[] args) {
    		System.out.println("     - int          :");
    		 System.out.println("sI="+sI);
    		 System.out.println("sInteger="+sInteger);
    
    		 System.out.println("     - char  String :");
    		 System.out.println("sC="+sC);
    		 System.out.println("sString="+sString);
    
    		 System.out.println("     - boolean  Boolean :");
    		 System.out.println("sB="+sB);
    		 System.out.println("sBoolean="+sBoolean);
    
    		 System.out.println("     - int,char     ");
    		 MemberVar memberVar = new MemberVar();
    		 System.out.println(memberVar.oInt);
    		 System.out.println(memberVar.oChar);
    	}
    }
    

    出力結果:
         - int          :
    sI=0
    sInteger=null
    
         - char  String :
    sC='\u0000' 								()
    sString=null
    
         - boolean  Boolean :
    sB=false
    sBoolean=null
    
         - int,char     
    0
    '\u0000'
    
    

    コード(二):局所変数テスト
    package variable;
    
    public class LocalVar {
    	
    	public static void main(String[] args) {
    		//    
    		int a = 0;
    		int b = 0;
    		int c;                          //           
    		//    
    		Integer i = null;
    		Integer j = null;
    		Integer k ;                     //           
    		
    		System.out.println(a);
    		System.out.println(b);
    		//System.out.println(c);		//     ,The local variable c may not have been initialized
    		System.out.println(i);
    		System.out.println(j);
    		//System.out.println(k);		//     ,The local variable c may not have been initialized
    	}
    
    }
    

    結論:
  • メンバー変数(静的変数、インスタンス変数)は明示的に初期化せずに宣言され、JVMが対応するクラスをロードすると、初期化されていないメンバー変数に暗黙的なデフォルト値が付与されます.メンバー変数はすべてメモリ領域のスタックに格納されるため、スタック内のデータはデフォルト値の付与を行います.
  • ローカル変数は明示的に初期化せずに宣言されるだけで、仮想マシンはローカル変数を暗黙的に初期化しません.ローカル変数はスタック領域ではなくメモリ領域のスタック領域に格納されるためです.

  • 注:ローカル変数が初期化されていない場合、変数が値を指していないため、呼び出されることは許可されません.でも二つのケースに分かれています
  • ローカル変数は初期化せずに宣言するだけで使用される場合、コンパイラを通過することはできません.エラー(ローカル変数は初期化が必要です)が発生します.ローカル変数はメモリ領域のスタックに格納されているので、呼び出す前に明示的に初期化する必要があります.
  • ローカル変数は宣言のみで初期化されず、次のコードでは使用されず、コンパイラでチェックできるものであり、その変数は他の場所で呼び出されていないため、コンパイラはその宣言をゴミとして削除する(後述する)
  • テスト2
    メンバー変数とローカル変数がfinalで修飾されている場合、デフォルト値が付与される場合はどうなりますか?
    public class FinalVar {
    
    	final static int a = 0;
    	final static Integer b = 0;
    	//final static int c;					//       ,   ,The blank final field c may not have been initialized
    	//final static Integer d;
    
    	final int i = 0;
    	final Integer j = 0;
    	//final int k;							//       ,   ,The blank final field k may not have been initialized
    	//final Integer l;
    
    	public static void main(String[] args) {
    		final int localA;					//            ,               , final  。
    		final Integer localB;	 			// final      ,                ,  final            
    
    		localA = 0;
    		//localA = 1;						//The final local variable localA may already have been assigned,final          
    
    	}
    }
    

    結論
  • finalメンバー変数は可変変数なので、JVMは暗黙的に初期化しないので、明示的に初期化操作を行う必要があります.finalメンバー変数の初期化には2つの選択肢しかありません.1つ目は宣言時に初期化付与を行うことです.2つ目は、宣言後、値を付けずにコンストラクタでthisに行きます.参照を初期化します.そうでなければ呼び出されなくてもコンパイルエラーが報告される
  • finalローカル変数はローカル変数と同様に暗黙的に初期化されず、表示されるように初期化操作を行う必要があるが、後に値を付与しないことを宣言し、後のコードで最初の初期化値付与操作を遅らせることができるが、最初の値付与後は値付与を許可しない.同様に呼び出されていないfinalローカル変数は、コンパイル時に宣言が削除されます.

  • テスト3
    jd-guiツールでコンパイル後のclassファイルを逆コンパイルし、違いを表示
    ソース:
    public class FinalVar {
    
    	final static int a = 0;
    	final static Integer b = 0;
    	static int c;
    	static Integer d;
    	
    	final int i = 0;
    	final Integer j = 0;
    	int k;
    	Integer l;
    	
    	public static void main(String[] args) {
    		final int localA;
    		localA = 0;					
    		final Integer localB;	 		
    		
    		int localC;
    		localC = 0;
    		Integer localD;
    
    	}
    }
    

    コンパイルされたコード:
    public class FinalVar
    {
      static final int a = 0;
      static final Integer b = Integer.valueOf(0);
      static int c;
      static Integer d;
      
      final int i = 0;
      final Integer j = Integer.valueOf(0);
      int k;
      Integer l;
      
      public static void main(String[] args)
      {
        int localA = 0;
        int localC = 0
      }
    }
    
    

    結論:
  • 初期化されていない局所変数を宣言した場合、有無にかかわらずfinal修飾は、コンパイラがゴミコードとして削除したものであり、localBlocalD両局所変数の宣言である.
  • ローカル変数の遅延初期化コードは、コンパイラにより最適化される.如int localA; localA = 0会别最适化成句话int localA = 0
  • Integerの箱詰め問題は、ここではまず座り込まない.

  • (したがって、ローカル変数が初期化を遅延し、メンバー変数が許可されない理由がわかります.メンバー変数が初期化されていないため、仮想マシンも暗黙的に初期化されますが、コンパイラも初期化されていないメンバー変数がゴミコードであるとは思いません.これはローカル変数とは異なります.例を挙げると、finalのメンバー変数は使用されていません.コンストラクタは初期化され、宣言時に付与文で初期化されていません.その後のコードでは初期化されません.このメンバー変数はfinal変数であるため、仮想マシンも初期化せず、コンパイラもメンバー変数の宣言を削除しません.このような値が格納されていないグローバルメンバー変数は、クラスがロードされるとメモリに割り当てられます.これはちょっとおかしいですね)
    最終結論:
  • メンバー変数(静的変数、インスタンス変数)にはデフォルト値があり、初期化しないと宣言するだけで、JVMは暗黙的に初期化します.メンバー変数がスタックに格納されているため
  • ローカル変数はデフォルト値がなく、JVMによって暗黙的に初期化されない.ローカル変数はスタックに格納されているから
  • final修飾された変数は、メンバー変数でもローカル変数でも可変ではない変数であり、明示的に初期化操作を行わなければならず、1回のみ付与される.
  • 初期化されていない局所変数は、使用されていない場合はコンパイル可能である.ただし、次のコードで使用した場合はコンパイルできません.メンバー変数の初期化が必要であることが示されます.
  • 初期化されていない局所変数(final修飾の有無にかかわらず)は、コンパイル中にコンパイラによってゴミコードとして削除される.

  • 補足:
  • 基本型変数はいずれも独自のデフォルト値を持ち、参照型のデフォルト値はnull
  • DataType
    Default Vaule
    byte
    0
    short
    0
    int
    0
    long
    0L
    float
    0.0f
    double
    0.0d
    char
    ‘\u0000’
    boolean
    false
    リファレンス変数
    null