※上記の広告は60日以上更新のないWIKIに表示されています。更新することで広告が下部へ移動します。

4. 型と値と変数

4.1. 型と変数の種類

4.2. プリミティブ型と値

4.3. 参照型と値

4.4. 型変数

4.5. 引数付き型

4.6. 型の抹消

4.7. 具象可能型

4.8. 未加工型

4.9. 交差型

4.10. サブタイプ化

4.11. 型の使用箇所

4.12. 変数

4.12.1. プリミティブ型の変数

4.12.2. 参照型の変数

4.12.3. 変数の種類

4.12.4. final変数

4.12.5. 変数の初期値

4.12.6. 型とクラスとインタフェース

Javaプログラミング言語では、全ての変数や全ての式はコンパイル時に決定可能な型を持っています。型はプリミティブ型か参照型です。参照型にはクラス型やインタフェース型も含みます。参照型はクラス宣言インタフェース宣言を含む型宣言によって導入されます。型という言葉をクラスやインタフェースを参照するのに用いることがしばしばあります。

Java仮想マシンでは、全てのオブジェクトはある特定のクラスに属しています。オブジェクトを生み出す作成式で書かれるクラスや、オブジェクトを生み出すのにClassオブジェクトのリフレクションメソッドが使用されるクラスや、文字列連結演算子+で暗黙的に作成されるオブジェクトのためのStringクラスがあります。このクラスをオブジェクトのクラスと呼びます。オブジェクトはそのクラスのインスタンスであり、そのクラスの全てのスーパークラスのインスタンスです。

全ての配列もクラスに属しています。配列オブジェクトに対しgetClassメソッドを呼び出すと配列のクラスを表す(Classクラスの)クラスオブジェクトを返します(10.8.)。

変数のコンパイル時の型は常に宣言されており、式のコンパイル時の型はコンパイル時に決定可能です。コンパイル時の型は変数が実行時にとりうる値や式が実行時にとりうる値を制限します。実行時の値がnullではない参照ならば、あるクラスのオブジェクトや配列を参照しています。そのクラスはコンパイル時の型と必ず互換性があります。

変数や式はコンパイル時の型がインタフェースであるかもしれません。インタフェースのインスタンスはありません。インタフェース型の変数や式はそのインタフェースを実装するクラスのオブジェクトを参照します(8.1.5.)。

時々、変数や式は"実行時の型"を持ちます。これは実行時の変数や式の値を参照する値がnullではないオブジェクトのクラスを参照します。

コンパイル時の型と実行時の型の間の一致は2つの理由から不完全です。:

1. 実行時、クラスやインタフェースはJava仮想マシンによってクラスローダーを使いロードされます。どのクラスローダーもそれ自身のクラスやインタフェースを定義しています。結果として、2つのローダーが等価なクラスやインタフェース定義をロードすることが可能ですが、実行時には異なるクラスやインタフェースとなります。結果として、もしそれをロードするクラスローダーが一致しなければ、正しくコンパイルされたコードはリンク時に失敗するかもしれません。

  詳しくは論文Dynamic Class Loading in the Java™ Virtual Machine、著者Sheng Liang、Gilad Bracha, Proceedings of OOPSLA '98、出版ACM SIGPLAN Notices、Volume 33、Number 10、1998年10月、ページ 36-44、およびThe Java™ Virtual Machine Specification, Java SE 7 Editionを参照してください。

2. 型変数型実引数は実行時に非具象可能です。結果として、実行時には同じクラスやインタフェースでもコンパイル時に複数の引数付き型で表されることがあります。特に、与えられたジェネリック型宣言(8.1.2.9.1.2.)のコンパイル時の呼び出しは全て単一の実行時の表現を共有します。

  特定の状況下で、引数付き型の変数が引数付き型ではないオブジェクトを参照することが可能です。この状況はヒープ汚染として知られています。変数は常に引数付き型を表すクラスのインスタンスであるオブジェクト参照します。

例4.12.6-1. 変数の型 対 オブジェクトのクラス

interface Colorable {
    void setColor(byte r, byte g, byte b);
}

class Point { int x, y; }

class ColoredPoint extends Point implements Colorable {
    byte r, g, b;
    public void setColor(byte rv, byte gv, byte bv) {
        r = rv; g = gv; b = bv;
    }
}

class Test {
    public static void main(String[] args) {
        Point p = new Point();
        ColoredPoint cp = new ColoredPoint();
        p = cp;
        Colorable c = cp;
    }
}

この例で:
  • Testクラスのmainメソッドの局所変数pPoint型であり、初期値としてPointクラスの新たなインスタンスを参照します。
  • 同様に局所変数cpColoredPoint型であり、初期値としてColoredPointクラスの新たなインスタンスを参照します。
  • 変数cpの値を変数pに代入することでpColoredPointオブジェクトへの参照を持ちます。これはColoredPointPointのサブクラスのため許可されています。ゆえにColoredPointクラスはPoint型と代入互換(assingment-compatible)です。ColoredPointオブジェクトはPointの全てのメソッドをサポートしています。その特有のフィールドrgbに加えて、Pointクラスのフィールド、すなわちxyも持ちます。
  • 局所変数cはインタフェース型Colorableです。変数はColorableを実装するクラスのオブジェクトへの参照を持つことができます。特にその変数はColoredPointへの参照を持つことができます。

インタフェースのインスタンスは作成できず、作成できるのはクラスのインスタンスだけなので、new Colorable()というような式は無効です。しかし、式new Colorable() { public void setColor... } は有効です。これはColorableインタフェースを実装した匿名クラス宣言であるからです。