TOPシステム開発> 【新・言語進化論】プロの言語仕様の読み方> 第2回:nullは何型? 型、値、変数を読み解く! (2/3)

【新・言語進化論】プロの言語仕様の読み方

【新・言語進化論】プロの言語仕様の読み方

第2回:nullは何型? 型、値、変数を読み解く!

著者:オープンストリーム 松下 雅和

監修者:オープンストリーム 高安 厚思

公開日:2007/11/13(火)

プリミティブ型の値の計算でなぜキャストが必要か?

intの値とlongの値を演算した場合、計算結果はlongの値となるため、int型に計算結果を格納するためにはintにキャストする必要があります。

このことについては知っている方も多いでしょう。では、なぜ計算結果はlongの値となるのでしょうか? なぜint型にキャストする必要があるのでしょうか? また、その理由を知っているでしょうか?

このような時に言語仕様を読むと謎が解けるのです。

言語仕様の「4.2.2 Integer Operations(整数演算)」には、「If an integer operator other than a shift operator has at least one operand of type long, then the operation is carried out using 64-bit precision, and the result of the numerical operator is of type long. If the other operand is not long, it is first widened (§5.1.5) to type long by numeric promotion (§5.6).(訳:シフト演算子以外の整数演算子のオペランドのいずれかがlong型である場合、演算は64ビットの精度で行われ、数値演算子の演算結果はlong型になる。この際、他方のオペランドがlong型でなければ数値の格上げ変換によってlong型へとワイドニング変換される)」とあります。

計算結果がlongの値となる理由は、intの値とlongの値を演算した場合、intの値は自動的にlong型へと変換され(プリミティブ型のワイドニング変換)、longの値同士の演算として処理されていたからです。

また、longの値をint型に格納するためには、「5.5 Casting Conversion(キャスト変換)」にあるように、キャスト変換によりプリミティブ型のナローイング変換を行う必要があります。さっきの疑問はこれで解決したでしょう。


(画像をクリックすると別ウィンドウに拡大図を表示します)

アンボクシング変換でNullPointerExceptionが発生する

Java 5から導入されたアンボクシング変換は、参照型の値を対応するプリミティブ型の値に変換する機能です(Integer型からint型など)。非常に強力な機能ですが、null参照に対してアンボクシング変換が要求された場合、NullPointerExceptionが発生してしまいます。

NullPointerExceptionが発生する原因は何でしょうか?

言語仕様の「5.1.8 Unboxing Conversion(5.1.8 アンボクシング変換)」には「If r is a reference of type Integer, then unboxing conversion converts r into r.intValue()(訳:rがInteger型の参照である場合、アンボクシング変換によってrはr.intValue()へと変換される)」とあります。

また「If r is a reference of type Long, then unboxing conversion converts r into r.longValue()(訳:rがLong型の参照である場合、アンボクシング変換によってrはr.longValue()へと変換される)」とあります。

参照型の値をプリミティブ型の値に変換する際は、Integer型の参照であればintValue()、Long型の参照であればlongValue()など、プリミティブ型の値を取得するメソッドが内部で呼ばれているのです。

null参照に対してはこのようなメソッドは実行できないため、「If r is null, unboxing conversion throws a NullPointerException(訳:rがnullの場合、アンボクシング変換によってNullPointerExceptionがスローされる)」と説明されています。これがNullPointerExceptionの発生する原因です。

ヒープ汚染の可能性

Java 5からジェネリックの仕様が追加され、クラスやインターフェース名に実型引数を指定したパラメータ化型(List<String>など)が利用可能となりました。これにともない、実型引数を指定しない従来の記述方法(Listなど)は未加工型と呼ばれるようになりました。

しかし、パラメータ化型の変数が、そのパラメータ化型のものでないオブジェクトを参照してしまう可能性は存在します。

例えば、図のようなコードを記述した場合、List<String>として宣言されたstringListが、実際にはList<Integer>の値を参照することになってしまいます。こういった状況は「ヒープ汚染」と呼ばれ、言語仕様の「4.12.2.1 Heap Pollution(ヒープ汚染)」で説明されています。

では、さらに深堀りして言語仕様の本質を見ていきましょう。 次のページ




株式会社オープンストリーム 松下 雅和
著者プロフィール
株式会社オープンストリーム 松下 雅和
ソフトウェアエンジニアリングラボラトリ システムズアーキテクト SOA担当
早稲田大学社会科学部卒。中堅SIerの研究開発部門に4年間所属し、JavaやXMLを用いたオープン系のシステム開発に携わった。現在は株式会社オープンストリームにてSOAを適用したプロジェクトに従事している。「なんでも楽しむ!」がモットー。
http://www.opst.co.jp/


株式会社オープンストリーム 高安 厚思
監修者プロフィール
株式会社オープンストリーム 高安 厚思
テクニカルコンピテンシーユニット 主管システムズアーキテクト
横浜国立大学経営学部卒。銀行系シンクタンクでオブジェクト指向技術の研究に携わった後、大手SIerにてアーキテクチャ構築、プロセス研究に携わった。現在株式会社オープンストリームにてSOAを中心とする研究開発およびアーキテクチャ構築に従事。最近はXMLのダイナミックさに魅了されている。
http://www.opst.co.jp/


INDEX
第2回:nullは何型? 型、値、変数を読み解く!
  監修から一言
プリミティブ型の値の計算でなぜキャストが必要か?
  言語仕様をさらに深堀り!