[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[jfriends-ml 10235] 定数パターンの インライン化問題



高橋(徹)です。

第3回読書会のタイプセーフenumの是非に関していろいろ意見が出てい
ます。タイプセーフな定数と、プリミティブ型/String型の定数とにつ
いて、コンパイルされた際のインライン問題についてはまだ出ていなか
ったようなので、以下にまとめます。
なお、検証に使った環境は以下のとおり。
OS : Windows2000
JDK: Sun JDK1.4.1 Beta

プリミティブ型やString型のpublic static finalなフィールドを参照
するコードをコンパイルすると、値自体がインライン化されます。

例)
public class Constants {
  public static final int INT_VALUE = 123;
  public static final String STRING_VALUE = "ABC";
}

public class Client {
  public static void main(String[] args) {
    int value = Constants.INT_VALUE;
    String name = Constants.STRING_VALUE;
  }
}

このコードをコンパイルしてjavapコマンドでディスアセンブルすると、
$ javap -c Client
    :
Method void main(java.lang.String[])
   0 sipush 789
   3 istore_1
   4 ldc #2 <String "XYZ">
   6 astore_2
   7 return

と、mainメソッドの中では値そのものが使われます。

定数を提供する側(ここではConstantsクラス)と定数を利用する側
(ここではClientクラス)が別々に開発されているような場合、定数に
変更があってもClientクラスを再コンパイルしない限り古い値を使い続
けることになります。
この辺りの仕様については、Java言語仕様の13.4.8項に述べられていま
す。
http://www.y-adagio.com/public/standards/tr_javalang2/binaryComp.
doc.html#45139

JLSでは、static finalなフィールドをpublicではなくprivateとし、こ
れをアクセッサを介して取り出すことを勧めています。

一方、タイプセーフな定数を使用すると、

  public static void main(String[] args) {
    Suit club = Suit.CLUBS;
      :
のコードは以下のようにバイトコンパイルされます。
Method void main(java.lang.String[])
   0 getstatic #17 <Field Suit CLUBS>

必ずSuitクラスに値を取りに行きます。


---
Toru TAKAHASHI
http://www.alles.or.jp/~torutk/oojava/