5

JavaのSwitchステートメントにCASEとしてFINAL変数を含めることができるのはなぜですか?##

私がチェックしたJDK7では、以下に示すように、値を最終変数に再割り当てすることはできません。しかし、最終変数「x」の値を再割り当てできないのに、なぜ最終変数「x」をケースのSwitchステートメントに含めることができるのでしょうか。

Oracleは、Javaコンパイラが初期化された値としてfinal変数を取得するが、変数名は取得しないと定義しているのに、なぜこれを実行できるのでしょうか。http://docs.oracle.com/javase/specs/jls/se7/html/jls-4.html#jls-4.12.4

これがJavaコンパイラの技術的なエラーなのか、それともSwitchステートメントの最終変数のケースをチェックする例外や特別な使用法があるのか​​教えてください。

class Example{
    public static void main(String args[]){
        final int x=100;
        //x=200;    //error: cannot assign a value to final variable x

        //The below piece of code compiles
        switch(x){
            case 200: System.out.println("200");
            case 300: System.out.println("300");
        }

    }
}
4

7 に答える 7

4

この状況はどうですか?

public class Foo
{
    private final int x;

    public Foo(int x){this.x = x;}

    public void boo()
    {
        switch(x)
        {
            case 200: System.out.println("200");
            case 300: System.out.println("300");
        }
    }
}

または多分これ:

public static void doSomething(final int x)
{
    switch(x)
    {
        case 200: System.out.println("200");
        case 300: System.out.println("300");
    }
}
于 2013-02-24T15:37:41.583 に答える
3
switch(x){
    case 200: System.out.println("200"); break;
    case 300: System.out.println("300");
}

本質的には

if (x == 200)
  System.out.println("200");
else if (x == 300)
  System.out.println("300");

を割り当てるのではなく比較するだけxなので、変更できないという事実は問題ではありません。

技術的には、あなたの例は少し異なります(あなたが持っていないためbreak):

if (x == 200)
  System.out.println("200");
if (x == 200 || x == 300)
  System.out.println("300");

またはそのようなもの。

コードがコンパイルされない、またはコンパイルされxないという事実。ただし、Java が switch ステートメントを最適化することを許可する場合があります。200300

于 2013-02-24T15:42:11.753 に答える
2

さて、final関数でパラメーターを渡すことができます:

//the function doesn't know what x  value is,
//but it knows that it can't modify its value
public someFunction(final int x) {

    x += 1; //compiler error
    switch(x) {
        case 200: System.out.println("200");
            break;
        case 300: System.out.println("300");
            break;
    }
}

//the function doesn't know what x value is,
//but it knows that it can modify it
//for internal usage
public someOtherFunction(int x) {

    switch(x) {
        case 200:
            x += 200;
            break;
        case 300:
            x += 300;
            break;
    }
    System.out.println(x);
}
于 2013-02-24T15:35:34.300 に答える
1

switchコンパイル時に常に同じケースに評価されることがわかっているステートメントを削除または警告するための最適化は、まれなケースであるため、コンパイラーには実装されていないと思います。

次のコードも、警告やエラーなしでコンパイルされます。

  switch(3){
    case 2: 
      System.out.println("two"); 
      break;
    case 3: 
      System.out.println("three"); 
      break;
  }

パーツ内の到達不能コードに関するコンパイラーによる警告case 2:は適切ですが、実装されていません。

于 2013-02-24T16:08:25.953 に答える
1

finalモディファイヤが違いを生むと期待するのはなぜですか? オンになっている値に何も割り当てる必要はありません。

switchステートメントの意味を理解していますか?

于 2013-02-24T15:40:14.963 に答える
0

ほとんどのコンパイラは、ヒューリスティック (経験に基づく手法) と近似に依存する最適化アルゴリズムを使用してコードを最適化します。以下のコードは、制御フロー分析に入ります。プログラムのサンプルをたくさん実行しました

ケース A) 最終変数を使用した if-else - コンパイラは警告デッド コードをスローします。生成されたバイト コードには、if-else ステートメントはありません。

public static void main(java.lang.String[])

Stack=1, Locals=2, Args_size=1
0:  iconst_0
1:  istore_1
2:  return
LineNumberTable: 
line 42: 0
line 54: 2

LocalVariableTable: 
Start  Length  Slot  Name   Signature
 0      3      0    args       [Ljava/lang/String;
 2      1      1    selection       I


 }

ケース B) 最終変数のない if-else - コンパイラ エラーはありませんが、コードの最適化もありません。

      final int selection i=100; //case A
      //int selection i=100; //case B

     if(selection==1){
         System.out.println("Hi");
  }else if(selection==2){

  }else{

   }

ケース C) if-else は final 変数ですが、if-else ステートメントは別のメソッドに入れられます。

       computeIfLese(int selection) 
  • このメソッドは、パラメーターの値が異なる他のインスタンスによって呼び出される可能性があるため、コード OPtimization は実行されません (明らかに)。

コンパイラーの最適化手法はヒューリスティックスに基づいているため、このケースはミスとして存在する可能性がありますが、最もまれなケースのうち最もまれなケースを誰が考えるでしょうか。

Java Gods からのコメントが待っていました... :)

これは、コンパイラがこれを最適化していないことを示す生きた証拠です。ラベル 5 を確認してください。

public static void main(java.lang.String[]);
Code:
 Stack=2, Locals=2, Args_size=1
0:  bipush  100
2:  istore_1
3:  bipush  100
5:  lookupswitch{ //2
    200: 32;
    300: 40;
    default: 48 }
32: getstatic   #16; //Field java/lang/System.out:Ljava/io/PrintStream;
35: ldc #22; //String 200
37: invokevirtual   #24; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
40: getstatic   #16; //Field java/lang/System.out:Ljava/io/PrintStream;
43: ldc #30; //String 300
45: invokevirtual   #24; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
48: return
  LineNumberTable: 
line 11: 0
line 15: 3
line 17: 32
line 18: 40
line 21: 48

LocalVariableTable: 
Start  Length  Slot  Name   Signature
0      49      0    args       [Ljava/lang/String;
3      46      1    selection       I

StackMapTable: number_of_entries = 3
 frame_type = 252 /* append */
 offset_delta = 32
 locals = [ int ]
  frame_type = 7 /* same */
 frame_type = 7 /* same */


 }
于 2013-02-25T23:52:32.477 に答える
0

最終的なパラメーターを持つことに加えて、最終的なローカル変数は、コンパイル時に不明な値を保持できます。

public static void main(String args[]){
    final int x;

    if (someMethod())
      x = 200;
    else
      x = 300;

    switch(x){
        case 200: System.out.println("200");
        case 300: System.out.println("300");
    }

}
于 2013-04-03T20:32:53.257 に答える