18

この場合を考えてみましょう:

public Class1 {
   public static final String ONE = "ABC";
   public static final String TWO = "DEF";
}

public Class2 {

  public void someMethod() {
    System.out.println(Class1.ONE + Class1.TWO);
  }
}

通常、コンパイラは1つと2つの定数をインライン化することを期待します。ただし、この動作は保証されていますか?クラスパスにClass1を指定せずに実行時にClass2をデプロイし、コンパイラに関係なく動作することを期待できますか、それともこれはオプションのコンパイラ最適化ですか?

編集:一体なぜこれを行うのですか?アプリケーションの両端(RMIを介したクライアントとサーバー)間で共有される定数があります。この特定のケースでは、その除算の片側にしか存在できないクラスに定数を配置すると非常に便利です(コードの両側で共有する必要があるという理由だけで、任意の定数クラスに含めるのではなく、論理的にはその定数値を所有するものであるためです。コンパイル時にはすべて1セットのソースファイルですが、ビルド時にはパッケージごとに分割されます。

4

6 に答える 6

24

これは定数式として扱われることが保証されており、JLSのセクション15.28によってインターンされることが保証されています。

コンパイル時定数式は、プリミティブ型の値または突然完了しない文字列を示す式であり、以下のみを使用して構成されます。

  • プリミティブ型のリテラルとString型のリテラル(§3.10.5)
  • プリミティブ型にキャストし、String型にキャストします
  • 単項演算子+、-、〜、および!(ただし、++または-ではありません)
  • 乗法演算子*、/、および%
  • 加法演算子+および-
  • ..。

..。

String型のコンパイル時定数は、String.internメソッドを使用して、一意のインスタンスを共有するために常に「インターン」されます。

さて、それはそれがインライン化されることが保証されているというわけではありません。ただし、仕様のセクション13.1には次のように記載されています。

定数変数(§4.12.4)であるフィールドへの参照は、コンパイル時に、示されている定数値に解決されます。そのような定数フィールドへの参照は、バイナリファイルのコードに存在してはなりません(定数フィールドを含むクラスまたはインターフェイスを除き、それを初期化するコードがあります)。また、そのような定数フィールドは常に初期化されているように見える必要があります。そのようなフィールドのタイプのデフォルトの初期値は決して守られてはなりません。

つまり、式自体が定数でなくても、への参照はありませんClass1。そうです、あなたは大丈夫です。これは必ずしも連結値がバイトコードで使用されることを保証するものではありませんが、前述のビットは連結値がインターンされることを保証するため、連結値をインライン化するだけではない場合は非常に驚きます。そうでない場合でも、がなくても動作することが保証されますClass1

于 2009-09-10T17:31:57.967 に答える
10

これをjavac1.6.0_14でコンパイルすると、次のバイトコードが生成されます。

public void someMethod();
  Code:
   0:   getstatic       #2; //Field java/lang/System.out:Ljava/io/PrintStream;
   3:   ldc     #3; //String ABCDEF
   5:   invokevirtual   #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
   8:   return

したがって、文字列はコンパイル時に連結され、結果はClass2の定数プールに含まれます。

于 2009-09-10T18:24:46.750 に答える
0

コンパイラによってインライン化されるのではなく、実行時にインタプリタによってインライン化され、可能であればアセンブリコードに変換されます。

すべてのインタープリター(JVM)が同じように機能するわけではないため、保証することはできません。しかし、最も重要な実装で十分です。

残念ながら、これを維持するためのリンクがありません:(

于 2009-09-10T18:04:56.390 に答える
0

これがうまくいくかどうかはわかりませんが、良い考えとは思えません。

これを行う「通常の」方法は次のとおりです。

  1. クライアントとサーバー間で共有されるパッケージに定数を入れます。おそらく、そのようなパッケージがあるのは、それがインターフェースの行き先だからです。
  2. そのようなパッケージがない場合は、共有定数を使用して2つのクラスを作成します。1つはサーバー用、もう1つはクライアント用です。
于 2009-09-10T18:05:57.403 に答える
0

JLS13.4.9を参照してください。定数がコンパイラーによってインライン化されることを明示的に要求する必要はありませんが、条件付きコンパイルとswitchステートメント内の定数のサポートにより、コンパイラーが常に定数をインライン化することを示唆しています。

于 2009-09-10T18:13:08.697 に答える
0

に組み込まれている機能の独自のバージョンをコーディングしているようです。これによりenum、とpublic static finalを介して適切な名前が付けられますname()toString()また、他のいくつかの利点もありますが、メモリフットプリントが大きくなるという欠点があります)。

列挙型がまだ含まれていない古いバージョンのJavaを使用していますか?

于 2009-09-10T19:08:10.740 に答える