【java解惑】ローカル変数宣言は文ブロックにのみ格納できます


次のコードを示します.
public class Example055 {

	private static long numCreated = 0;

	public Example055() {
		numCreated++;
	}

	public static long numCreated() {
		return numCreated;
	}

	public static void main(String[] args) {
		for(int i=0;i<10;i++)
			Example055 e55 = new Example055(); //1
		System.out.println(Example055.numCreated());
		
	}
}

出力の説明:
このプログラムはコンパイルできません.問題は位置1にある.
コード解析:
ローカル変数宣言は文のように見えますが、技術的にはそうではありません.ローカル変数宣言文であるべきです.Java言語仕様では、ローカル変数宣言文をfor、while、doサイクルで繰り返し実行する文として許可しません.ローカル変数宣言は、文として1つの文ブロックにのみ直接表示されます.(文ブロックは、括弧のペアと、その括弧のペアに含まれる文と宣言で構成されます.)
したがって、上記のプログラムは変更する必要があります.宣言をキャンセルしたり、文ブロックを追加したりすることができます.
    /**  1: */
		for(int i=0;i<10;i++){
			Example055 e55 = new Example055();
		}
		System.out.println(Example055.numCreated());
		
		/** 2: , */
		for(int i=0;i<10;i++)
			new Example055();
		
		System.out.println(Example055.numCreated());

修正することで、プログラムは結果を正しくコンパイルして出力することができます.しかし、変更されたプログラムでは、マルチスレッドを使用して実行すると、プログラムにエラーが発生する可能性があります.つまり、上記のプログラムはスレッドセキュリティではありません.1つの変更方法は、スレッド同期を追加することです.
public class Example055Safe {

	private static long numCreated = 0;

	public Example055Safe() {
		synchronized (Example055Safe.class) {
			numCreated++;
		}
	}

	public synchronized static long numCreated() {
		return numCreated;
	}
	
	public static void main(String[] args) {

		/*
		 * for(int i=0;i<10;i++) Example055 e55 = new Example055();
		 * System.out.println(Example055.numCreated());
		 */

		/**  1:  */
		for (int i = 0; i < 10; i++) {
			Example055Safe e55 = new Example055Safe();
		}
		System.out.println(Example055Safe.numCreated());

		/**  2: ,  */
		for (int i = 0; i < 10; i++)
			new Example055Safe();

		System.out.println(Example055Safe.numCreated());
	}
}

JDK 1.5以降は、上記のsynchronizedを使用することなく、従来のlongの代わりにAtomicLongを使用することでスレッド同期の問題を解決することもできる.
    private static AtomicLong numCreated = new AtomicLong();

	public Example055AtomicLong() {
		numCreated.incrementAndGet();
	}

	public synchronized static long numCreated() {
		return numCreated.get();
	}

    
要するに、ローカル変数宣言は、for、while、またはdoループの繰り返し実行文として使用することはできません.1つの文として1つの文ブロックにのみ表示されます.また、変数を使用してインスタンスの作成をカウントする場合は、intタイプの変数ではなくlongタイプの変数を使用してオーバーフローを防止します.最後に、マルチスレッドでインスタンスを作成する場合は、インスタンスカウンタへのアクセスを同期するか、AtomicLongタイプのカウンタを使用します.
注:本「java解惑」シリーズは、ブロガーが「java解惑」の原書を読んだ後、原書の説明と例の部分を改編し、博文として発表したものです.すべての例はgithubで直接テストに合格し、共有されています.これらの例を通じて自分を励まして他人に恩恵を与える.また、このシリーズのすべてのブログは、ブロガー個人の微信公衆番号で「愛題猿」や「ape_it」を検索して読むことができます.もし文章の中に原作者の権利を侵害する内容があれば、直ちにブロガーに知らせて、直ちに削除してください.もし読者が文章の中の内容に異議があれば、ブログの伝言や微信の公衆番号の伝言などの方法で共同で検討することを歓迎します.
ソースアドレスhttps://github.com/rocwinger/java-disabuse
本文は“winger”のブログから出て、転載をお断りします!