「5. 変換と昇格」(2012/09/13 (木) 23:33:18) の最新版変更点
追加された行は緑色になります。
削除された行は赤色になります。
*5. 変換と昇格
Javaプログラミング言語で書かれた全ての式は、式の構造やその式の中に記述されたリテラルや変数やメソッドの型から推論
できる型を持ちます。しかし、式の型が適切ではない文脈で式を書くこともできます。ある場合には、これはコンパイル時に
エラーを引き起こします。他のケースでは、その式の型に関連する型を受理することができる文脈もあります。便宜上、プロ
グラマーは明示的に型変換を要求する代わりに、Javaプログラミング言語は式の型をその周囲の文脈に合わせて受理すること
が可能な型に暗黙的&i(){変換(conversion)}を行います。
型Sから型Tへの特定の変換は型Sの式をあたかも型Tであるかのようにコンパイル時に扱えるようにします。変換の正当性を検
査するために、または実行時の式の値を新たな型Tに対する適切な形式に変換するために、これは実行時に対応するアクション
が必要になることがあります。
#divstyle(background-color:#f0f0ff;border:1px solid black;padding 4px){{{
&bold(){&aname(ex5.0-1,option=nolink){例5.0-1. コンパイル時と実行時の変換}}
-&i(){&small(){&tt(){Object}型から&tt(){Thread}型への変換は実行時の値が実際に&tt(){Thread}クラスまたはそのサブク
ラスのインスタンスかどうか確かめるための実行時検査が必要です。そうでなければ、例外がスローされます。}}
-&i(){&small(){&tt(){Thread}型から&tt(){Object}型への変換は実行時のアクションを必要としません。&tt(){Thread}は
&tt(){Object}のサブクラスであるため、&tt(){Thread}型の式で生成されるいかなる参照も&tt(){Object}型の有効な参照値と
なります。}}
-&i(){&small(){&tt(){int}型から&tt(){long}型への変換は実行時に符号付き32ビット整数値の64ビット表現が必要とされま
す。情報は失われません。
-&i(){&small(){&tt(){double}型から&tt(){long}型への変換は64ビット浮動小数点値から64ビット整数表現への自明でない変
換を必要とします。実際の実行時の値により、情報は失われるかもしれません。
}}}
どの変換文脈でも、特定の変換のみが許可されています。記述を簡便にするために、Javaプログラミング言語で可能な特定の
変換をいくつかの広範囲なカテゴリーにグループ分けします。:
-恒等変換
-拡幅プリミティブ変換
-縮幅プリミティブ変換
-拡幅参照変換
-縮幅参照変換
-ボックス化変換
-ボックス化解除変換
-未検査変換
-捕捉変換
-文字列変換
-値集合変換
式の変換が起こる際に5つの&i(){変換文脈(conversion context)}が存在します。どの文脈も上記に挙げたカテゴリーのいくつ
かの変換は許可し、その他は許可しません。"変換"という語はそのような文脈で特定の変換を選択する処理を記述するのにも
使用します。例えば、メソッド呼び出し内の実引数である式を"メソッド呼び出し変換"と呼ぶことにします。これはメソッド
呼び出し実引数文脈のための規則に従って暗黙的にその式に合った特定の変換が選択されるという意味です。
変換文脈の1つは&tt(){+}や&tt(){*}のような数値演算子のオペランドです。そのようなオペランドに対す変換処理は&i(){数
値昇格(numeric promotion)}と呼ばれます。昇格は二項演算子の場合に特別で,一方のオペランドに対する変換の選択が,他
方のオペランド式の型に部分的に依存する可能性があります。
本章ではまず初めに変換の11のカテゴリーについて記述します([[5.1.>5.1. 変換の種類]])。そこには[[文字列連結演算子
+>15.18.1. 文字列連結演算子+]]に許された&tt(){String}への特別変換が含まれます。次に、5つの変換文脈について記述し
ます。:
-[[代入変換>5.2. 代入変換]]([[15.26.>15.26. 代入演算子]])は式の型を特定の変数の型へ変換します。
代入変換は&tt(){OutOfMemoryError}([[ボックス化変換>5.1.7. ボックス化変換]]の結果)や&tt(){NullPointerException}
([[ボックス化解除変換>5.1.8. ボックス化解除変換]]の結果)や&tt(){ClassCastException}([[未検査変換>5.1.9. 未検査変
換]]の結果)を実行時にスローする可能性があります。
-[[メソッド呼び出し変換>5.3. メソッド呼び出し変換]]([[15.9.>15.9. クラスインスタンス作成式]]、[[15.12.>15.12. メ
ソッド呼び出し式]])はメソッドやコンストラクター呼び出し内の各実引数に適用され、1つの例外を除いて、代入変換と同じ
変換を行います。
メソッド呼び出し変換は&tt(){OutOfMemoryError}([[ボックス化変換>5.1.7. ボックス化変換]]の結果)や&tt()
{NullPointerException}([[ボックス化解除変換>5.1.8. ボックス化解除変換]]の結果)や&tt(){ClassCastException}([[未検
査変換>5.1.9. 未検査変換]]の結果)を実行時にスローする可能性があります。
-[[キャスト変換>5.5. キャスト変換]]は式の型を[[キャスト演算子>15.16. キャスト式]]によって明示的に指定された型へ変
換します。
これは代入変換やメソッド呼び出し変換より包括的です。文字列変換以外に任意の特定変換が許可されます。しかし、参照
型へのキャストは実行時に例外を生じる可能性があります。
-[[文字列変換>5.4. 文字列変換]]は他方のオペランドが&tt(){String}で自身が&tt(){String}以外の2項&tt(){+}演算子のオ
ペランドにのみ適用されます。
文字列変換は&tt(){OutOfMemoryError}([[クラスインスタンス作成>12.5. 新しいクラスインスタンスの作成]]の結果)を実
行時にスローする可能性があります。
-[[数値昇格>5.6. 数値昇格]]は数値演算子のオペランドをその式を処理する共通の型に変換します。
#divstyle(background-color:#f0f0ff;border:1px solid black;padding 4px){{{
&bold(){&aname(ex5.0-2,option=nolink){例5.0-2. 変換文脈}}
class Test {
public static void main(String[] args) {
// Casting conversion (5.4) of a float literal to
// type int. Without the cast operator, this would
// be a compile-time error, because this is a
// narrowing conversion (5.1.3):
int i = (int)12.5f;
// String conversion (5.4) of i's int value:
System.out.println("(int)12.5f==" + i);
// Assignment conversion (5.2) of i's value to type
// float. This is a widening conversion (5.1.2):
float f = i;
// String conversion of f's float value:
System.out.println("after float widening: " + f);
// Numeric promotion (5.6) of i's value to type
// float. This is a binary numeric promotion.
// After promotion, the operation is float*float:
System.out.print(f);
f = f * i;
// Two string conversions of i and f:
System.out.println("*" + i + "==" + f);
// Method invocation conversion (5.3) of f's value
// to type double, needed because the method Math.sin
// accepts only a double argument:
double d = Math.sin(f);
// Two string conversions of f and d:
System.out.println("Math.sin(" + f + ")==" + d);
}
}
&i(){&small(){このプログラムは以下を出力します。:}}
(int)12.5f==12
after float widening: 12.0
12.0*12==144.0
Math.sin(144.0)==-0.49102159389846934
**[[5.1. 変換の種類]]
**[[5.2. 代入変換]]
**[[5.3. メソッド呼び出し変換]]
**[[5.4. 文字列変換]]
**[[5.5. キャスト変換]]
**[[5.6. 数値昇格]]
*5. 変換と昇格
Javaプログラミング言語で書かれた全ての式は、式の構造やその式の中に記述されたリテラルや変数やメソッドの型から推論できる型を持ちます。しかし、式の型が適切ではない文脈で式を書くこともできます。ある場合には、これはコンパイル時にエラーを引き起こします。他のケースでは、その式の型に関連する型を受理することができる文脈もあります。便宜上、プログラマーは明示的に型変換を要求する代わりに、Javaプログラミング言語は式の型をその周囲の文脈に合わせて受理することが可能な型に暗黙的に&i(){変換(conversion)}を行います。
型Sから型Tへの特定の変換は型Sの式をあたかも型Tであるかのようにコンパイル時に扱えるようにします。変換の正当性を検査するために、または実行時の式の値を新たな型Tに対する適切な形式に変換するために、これは実行時に対応するアクションが必要になることがあります。
#divstyle(background-color:#f0f0ff;border:1px solid black;padding 4px){{{
&bold(){&aname(ex5.0-1,option=nolink){例5.0-1. コンパイル時と実行時の変換}}
-&i(){&small(){&tt(){Object}型から&tt(){Thread}型への変換は実行時の値が実際に&tt(){Thread}クラスまたはそのサブクラスのインスタンスかどうか確かめるための実行時検査が必要です。そうでなければ、例外がスローされます。}}
-&i(){&small(){&tt(){Thread}型から&tt(){Object}型への変換は実行時のアクションを必要としません。&tt(){Thread}は&tt(){Object}のサブクラスであるため、&tt(){Thread}型の式で生成されるいかなる参照も&tt(){Object}型の有効な参照値となります。}}
-&i(){&small(){&tt(){int}型から&tt(){long}型への変換は実行時に符号付き32ビット整数値の64ビット表現が必要とされます。情報は失われません。}}
-&i(){&small(){&tt(){double}型から&tt(){long}型への変換は64ビット浮動小数点値から64ビット整数表現への自明でない変換を必要とします。実際の実行時の値により、情報は失われるかもしれません。}}
}}}
どの変換文脈でも、特定の変換のみが許可されています。記述を簡便にするために、Javaプログラミング言語で可能な特定の変換をいくつかの広範囲なカテゴリーにグループ分けします。:
-恒等変換
-拡幅プリミティブ変換
-縮幅プリミティブ変換
-拡幅参照変換
-縮幅参照変換
-ボックス化変換
-ボックス化解除変換
-未検査変換
-捕捉変換
-文字列変換
-値集合変換
式の変換が起こる際に5つの&i(){変換文脈(conversion context)}が存在します。どの文脈も上記に挙げたカテゴリーのいくつかの変換は許可し、その他は許可しません。"変換"という語はそのような文脈で特定の変換を選択する処理を記述するのにも使用します。例えば、メソッド呼び出し内の実引数である式を"メソッド呼び出し変換"と呼ぶことにします。これはメソッド呼び出し実引数文脈のための規則に従って暗黙的にその式に合った特定の変換が選択されるという意味です。
変換文脈の1つは&tt(){+}や&tt(){*}のような数値演算子のオペランドです。そのようなオペランドに対す変換処理は&i(){数値昇格(numeric promotion)}と呼ばれます。昇格は二項演算子の場合に特別で,一方のオペランドに対する変換の選択が,他方のオペランド式の型に部分的に依存する可能性があります。
本章ではまず初めに変換の11のカテゴリーについて記述します([[5.1.>5.1. 変換の種類]])。そこには[[文字列連結演算子+>15.18.1. 文字列連結演算子+]]に許された&tt(){String}への特別な変換が含まれます。次に、5つの変換文脈について記述します。:
-[[代入変換>5.2. 代入変換]]([[15.26.>15.26. 代入演算子]])は式の型を特定の変数の型へ変換します。
代入変換は&tt(){OutOfMemoryError}([[ボックス化変換>5.1.7. ボックス化変換]]の結果)や&tt(){NullPointerException}([[ボックス化解除変換>5.1.8. ボックス化解除変換]]の結果)や&tt(){ClassCastException}([[未検査変換>5.1.9. 未検査変換]]の結果)を実行時にスローする可能性があります。
-[[メソッド呼び出し変換>5.3. メソッド呼び出し変換]]([[15.9.>15.9. クラスインスタンス作成式]]、[[15.12.>15.12. メソッド呼び出し式]])はメソッドやコンストラクター呼び出し内の各実引数に適用され、1つの例外を除いて、代入変換と同じ変換を行います。
メソッド呼び出し変換は&tt(){OutOfMemoryError}([[ボックス化変換>5.1.7. ボックス化変換]]の結果)や&tt(){NullPointerException}([[ボックス化解除変換>5.1.8. ボックス化解除変換]]の結果)や&tt(){ClassCastException}([[未検査変換>5.1.9. 未検査変換]]の結果)を実行時にスローする可能性があります。
-[[キャスト変換>5.5. キャスト変換]]は式の型を[[キャスト演算子>15.16. キャスト式]]によって明示的に指定された型へ変換します。
これは代入変換やメソッド呼び出し変換より包括的です。文字列変換以外の任意の特定変換が許可されます。しかし、参照型へのキャストは実行時に例外を生じる可能性があります。
-[[文字列変換>5.4. 文字列変換]]は他方のオペランドが&tt(){String}で自身が&tt(){String}以外の2項&tt(){+}演算子のオペランドにのみ適用されます。
文字列変換は&tt(){OutOfMemoryError}([[クラスインスタンス作成>12.5. 新しいクラスインスタンスの作成]]の結果)を実行時にスローする可能性があります。
-[[数値昇格>5.6. 数値昇格]]は数値演算子のオペランドをその式を計算する共通の型に変換します。
#divstyle(background-color:#f0f0ff;border:1px solid black;padding 4px){{{
&bold(){&aname(ex5.0-2,option=nolink){例5.0-2. 変換文脈}}
class Test {
public static void main(String[] args) {
// Casting conversion (5.4) of a float literal to
// type int. Without the cast operator, this would
// be a compile-time error, because this is a
// narrowing conversion (5.1.3):
int i = (int)12.5f;
// String conversion (5.4) of i's int value:
System.out.println("(int)12.5f==" + i);
// Assignment conversion (5.2) of i's value to type
// float. This is a widening conversion (5.1.2):
float f = i;
// String conversion of f's float value:
System.out.println("after float widening: " + f);
// Numeric promotion (5.6) of i's value to type
// float. This is a binary numeric promotion.
// After promotion, the operation is float*float:
System.out.print(f);
f = f * i;
// Two string conversions of i and f:
System.out.println("*" + i + "==" + f);
// Method invocation conversion (5.3) of f's value
// to type double, needed because the method Math.sin
// accepts only a double argument:
double d = Math.sin(f);
// Two string conversions of f and d:
System.out.println("Math.sin(" + f + ")==" + d);
}
}
&i(){&small(){このプログラムは以下を出力します。:}}
(int)12.5f==12
after float widening: 12.0
12.0*12==144.0
Math.sin(144.0)==-0.49102159389846934
}}}
**[[5.1. 変換の種類]]
**[[5.2. 代入変換]]
**[[5.3. メソッド呼び出し変換]]
**[[5.4. 文字列変換]]
**[[5.5. キャスト変換]]
**[[5.6. 数値昇格]]
表示オプション
横に並べて表示:
変化行の前後のみ表示: