目次 | | | 索引 Java言語規定
第2版

5. 変換及び昇格

Java言語で記述されたすべての式は,その式の構造,並びに,その式の中に記述された,リテラル,変数及びメソッドの型から演繹できる型をもつ。しかし,式の型が適切でない式を書いてしまうこともできるので,コンパイル時にエラーとなる場合もある。 例えば,if(14.9)内の式がboolean 以外の型をもてば,コンパイル時エラーが発生する。文脈によっては,式の型が受理可能な場合もある。Java言語では,プログラマに明示的型変換を要求するかわりに,指定された式の型から,式をとりまく文脈にとって受理可能な型への暗黙的な 変換(conversion) を実行することを図る。

S から型 T への特定の変換によって,型 S の式を,あたかも型 T をもつかのようにコンパイル時に扱うことができる。この変換の正当性を検査する実行時動作,又は式の実行時の値を新しい型 T にとって適切な形式に翻訳する実行時動作が,必要となる場合もある。その例を次に示す。

doubleから型longへの変換は,64ビット浮動小数点の値から64ビット整数表現への自明でない翻訳を要求する。実際の実行時の値によっては,情報が失われることがある。

すべての変換の文脈で,決められた特定の変換だけが許される。Javaプログラム言語で可能な特定の変換を,記述の便宜を図るために,次の大分類に類別する。

式の変換が発生可能な 変換の文脈(conversion context) には5種類ある。個々の文脈で,可能な変換を定めた。"変換" という用語は,文脈に対して特定の変換を選択する過程を記述するためにも使用する。例えば,メソッド呼出しで実引数の式が,"メソッド呼出し変換" に従う,というが,これはメソッド呼出し実引数の文脈に対する規則によって,その式に合った特定の変換を暗黙的に選択することを意味する。

変換文脈の中には,+*などの数値演算子のオペランドとなる数値がある。この数値オペランドの変換過程を 数値昇格(numeric promotion) と呼ぶ。二項演算子の場合は,一方のオペランドに対する変換の選択が,他方のオペランド式の型に部分的に依存する可能性がある。 5.では,最初に,文字列の連結演算子+に対して許されるStringへの特殊な変換を含む,変換の七つの大分類(5.1)を規定する。次に,五つの変換文脈を規定する。

変換に対する種々の文脈の例を次に示す。
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);
	}
}
これは,次の出力を生成する。

(int)12.5f==12
after float widening: 12.0
12.0*12==144.0
Math.sin(144.0)==-0.49102159389846934

5.1 変換の種別

Javaプログラム言語における型変換を,次の七つに大分類する。

5.1.1 恒等変換

ある型からそれと同じ型への変換は,いかなる型に対しても許される。

これは,二つの実用的な効果をもつ。第一に,すべての式は変換を受ける,と規則を簡潔に言明できる。第二に,明確化のために,プログラムが冗長なキャスト演算子を含むことを許可する。

booleanを含む唯一許される変換は,booleanからbooleanへの恒等変換とする。

5.1.2 プリミティブ型の拡大変換

プリミティブ型における次の19個の変換をプリミティブ型の拡大変換(widening primitive conversion) と呼ぶ。

プリミティブ型の拡大変換は,数値の大きさについての情報を失わない。実際,整数の型から他の整数の型への拡大変換及び型floatから型doubleへの拡大変換は,いかなる情報も失うことはない。つまり,数値を正確に保存する。 同じく,strictfp式での型floatから型doubleへの拡大変換も,数値を正確に保存する。しかし,strictfpでない変換は,変換後の数値の大きさについての情報を失うかもしれない。

int若しくはlongの値からfloatへの変換,又はlongの値からdoubleへの変換は,精度の損失(loss of precision),すなわち値の最小位の数ビットを失うことがある。この場合,浮動小数点の結果値は,IEEE 754直近へのまるめモード(4.2.4)を利用して,正しく丸めた整数値とする。

符号付き整数値の整数型 T への拡大変換は,単により長い桁を埋めるために整数値の2の補数表現について符号拡張をするだけとする。文字から整数型 T への拡大変換は,より長い桁を埋めるために文字値の表現をゼロ拡張する。

精度の損失が発生する可能性があるという事実にもかかわらず,プリミティブ型間の拡大変換は,実行時例外(11.)を生じない。

精度を失う拡大変換の例を次に示す。

class Test {
	public static void main(String[] args) {
		int big = 1234567890;
		float approx = big;
		System.out.println(big - (int)approx);
	}
}
これは,次を印字する。

-46
この例は,型intから型floatに変換する過程で,型floatの値が9桁の有効数字の精度がないために,情報が失われたことを示している。

5.1.3 プリミティブ型の縮小変換

プリミティブに関する次の23個の変換をプリミティブ型の縮小変換(narrowing primitive conversion) と呼ぶ。

縮小変換は,数値の大きさの情報を失うことがあり,さらに精度を失うこともある。

符号付き整数の整数型 T への縮小変換は,単に下位nビット以外のすべての情報を捨てる。ここで,n は,型 T を表現するのに使用するビット数とする。数値の大きさに関する情報の損失の可能性に加えて,結果値の符号が,入力値の符号と異なってしまうことがある。

同様にして,文字型から整数型 T への縮小変換は,単に下位nビット以外のすべての情報を捨てる。ここで n は,型 T を表現するのに使用するビット数とする。数値の大きさに関する情報の損失の可能性に加えて,文字が16ビットの符号なし整数値を表わすにもかかわらず,結果値が,負の数になることがある。

浮動小数点数から整数型 T への縮小変換は,二つの段階を踏む。

  1. 第一段階では,浮動小数点数を,Tlongならばlongに変換し,Tbyteshortchar又はintならばintに変換する。
  2. 第二段階は,次のとおりとする。
次に例を示す。

class Test {
	public static void main(String[] args) {
		float fmin = Float.NEGATIVE_INFINITY;
		float fmax = Float.POSITIVE_INFINITY;
		System.out.println("long: " + (long)fmin +
				".." + (long)fmax);
		System.out.println("int: " + (int)fmin +
				".." + (int)fmax);
		System.out.println("short: " + (short)fmin +
				".." + (short)fmax);
		System.out.println("char: " + (int)(char)fmin +
				".." + (int)(char)fmax);
		System.out.println("byte: " + (byte)fmin +
				".." + (byte)fmax);
	}
}
これは,次を出力する。

long: -9223372036854775808..9223372036854775807
int: -2147483648..2147483647
short: 0..-1
char: 0..65535
byte: 0..-1

charint及びlongに対する結果は,その型の最小及び最大表現可能値を生成する。

byte及びshortに対する結果は,符号及び数値の大きさに関する情報を失い,精度も失う。 この結果は,intの最小数及び最大数の下位ビットを調べることにより理解できる。 最小のintは16進で0x80000000であって,最大のint0x7fffffffである。 これから,shortの結果が値の下位16ビット,つまり0x0000及び0xffffとなることが説明される。 またcharの結果もまた,これらの値の下位16ビット,つまり'\u0000'及び'\uffff'となることで説明される。更にbyteの結果が,これらの値の下位8ビット,つまり0x00及び0xffとなることで説明される。 オーバフロー,アンダフロー又はその他の情報の損失が生ずる可能性があるという事実にもかかわらず,プリミティブ型間の縮小変換は,実行時例外(11.)を生じない。

情報を損失する多くの縮小変換を例示する,小さなテストプログラムを次に示す。

class Test {
	public static void main(String[] args) {

		// A narrowing of int to short loses high bits:
		System.out.println("(short)0x12345678==0x" +
				Integer.toHexString((short)0x12345678));

		// A int value not fitting in byte changes sign and magnitude:
		System.out.println("(byte)255==" + (byte)255);

		// A float value too big to fit gives largest int value:
		System.out.println("(int)1e20f==" + (int)1e20f);

		// A NaN converted to int yields zero:
		System.out.println("(int)NaN==" + (int)Float.NaN);
		
		// A double value too large for float yields infinity:
		System.out.println("(float)-1e100==" + (float)-1e100);

		// A double value too small for float underflows to zero:
		System.out.println("(float)1e-50==" + (float)1e-50);
	}
}
このテストプログラムは次の出力を生成する。

(short)0x12345678==0x5678
(byte)255==-1
(int)1e20f==2147483647
(int)NaN==0
(float)-1e100==-Infinity
(float)1e-50==0.0

5.1.4 参照型の拡大変換

次の変換を 参照型の拡大変換(widening reference conversion) と呼ぶ。

これらの変換は,実行時に特別な動作を要求せず,従って実行時に例外を投げない。これは,参照が他の型をもつことはコンパイル時に検証できるので成立する。

クラスの詳細な規定については8.を,インタフェースについては9.を,配列については10.を参照のこと。

5.1.5 参照型の縮小変換

次の変換を 参照型の縮小変換(narrowing reference conversion) と呼ぶ。

これらの変換は,実参照値が新しい型に適切な値かどうか調べるために,実行時に検査を要求する。適切な値でなければ,ClassCastExceptionが投げられる。

5.1.6 文字列変換

空型を含めてすべての型から型Stringへの文字列変換が存在する。

5.1.7 禁止される変換

5.1.8 値集合変換

値集合変換(Value set conversion) は,その型を変更せずに,ある値集合から別の値集合に浮動小数点式値を写像する処理とする。

FP厳密(FP-strict)(15.4)でない式中では,値集合変換はJavaプログラム言語の実装に選択肢をもたせる。

FP厳密式(15.4)中では,値集合変換の選択肢は無い。すべての実装は,同一の動作をしなければならない。

FP厳密式中で,FP厳密と宣言していないメソッドを起動し,そして実装を,浮動小数点数値集合の要素としてメソッド呼出しの結果を表わすことに決めた場合に限り,単精度指数部拡張数値集合又は,倍精度指数部拡張数値集合から値の写像が必要である。

FP厳密なコードである無いにかかわらず,値集合変換は常にfloat又はdouble以外の型の値を変えない。

5.2 代入変換

代入変換(assignment conversion) は,式の値を変数に代入する(15.26)ときに発生する。式の型は変数の型に変換しなければならない。代入文脈では,恒等変換(5.1.1),プリミティブ型の拡大変換(5.1.2)又は参照型の拡大変換(5.1.4)の使用が許される。更に,次の条件をすべて満足すれば,プリミティブ型の縮小変換を使用してもよい。 式の型が,代入文脈で許される変換によって変数の型へ変換できなければ,コンパイル時エラーが発生する。

変数の型がfloat又はdoubleの場合,値集合変換は型変換の後に適用される。

式の型が代入変換によって変数の型に変換可能ならば,その式(又はその式の値)は,その変数に対して 代入可能(assignable to) 又は等価だが,式の型は変数の型と 代入互換(assignment compatible with) とする。 代入変換は,例外を発生しない。(しかし,配列の要素を含む特別な場合には,代入が例外を生じることがあるので注意すること。10.10及び15.26.1を参照のこと。)

コンパイル時の定数の縮小とは,次のようなコードを許すことを意味する。

byte theAnswer = 42;
縮小がなければ,整数リテラル42は型intをもつという事実は,byteへのキャストを要求することになる。

byte theAnswer = (byte)42;		// cast is permitted but not required
プリミティブ型の値は,参照型の変数に代入してはならない。これを実行しようとすると,コンパイル時エラーを生じる。型booleanの値は,型booleanの変数にのみ代入できる。

次のテストプログラムは,プリミティブ型の値の代入変換に関する例を含む。

class Test {
	public static void main(String[] args) {
		short s = 12;		// narrow 12 to short
		float f = s;			// widen short to float
		System.out.println("f=" + f);

		char c = '\u0123';
		long l = c;			// widen char to long
		System.out.println("l=0x" + Long.toString(l,16));

		f = 1.23f;
		double d = f;		// widen float to double
		System.out.println("d=" + d);
	}
}
このプログラムは,次の出力を生成する。

f=12.0	
l=0x123
d=1.2300000190734863
しかし,次のテストプログラムは,コンパイル時エラーとなる。

class Test {
	public static void main(String[] args) {
		short s = 123;
		char c = s;		// error: would require cast
		s = c;			// error: would require cast
	}
}
その理由は,すべてのshort値がchar値ではないし,すべてのchar値がshort値でもないからとする。

空型の値(空参照が唯一その値)は,あらゆる参照型に代入可能で,その結果は,その型の空参照とする。

参照の代入を例示する例題を次に示す。

public class Point { int x, y; }
public class Point3D extends Point { int z; }
public interface Colorable {
	void setColor(int color);
}
public class ColoredPoint extends Point implements Colorable 
{
	int color;
	public void setColor(int color) { this.color = color; }
}
class Test {
	public static void main(String[] args) {
		// Assignments to variables of class type:
		Point p = new Point();
		p = new Point3D();	// ok: because Point3D is a
					// subclass of Point

		Point3D p3d = p;	// error: will require a cast because a 
					// Point might not be a Point3D
					// (even though it is, dynamically,
					// in this example.)

		// Assignments to variables of type Object:
		Object o = p;	// ok: any object to Object
		int[] a = new int[3];
		Object o2 = a;	// ok: an array to Object

		// Assignments to variables of interface type:
		ColoredPoint cp = new ColoredPoint();
		Colorable c = cp;	// ok: ColoredPoint implements
					// Colorable

		// Assignments to variables of array type:
		byte[] b = new byte[4];
		a = b;			// error: these are not arrays
					// of the same primitive type
		Point3D[] p3da = new Point3D[3];
		Point[] pa = p3da;	// ok: since we can assign a
					// Point3D to a Point
		p3da = pa;		// error: (cast needed) since a Point
					// can't be assigned to a Point3D
	}

}

コンパイル時参照型 S(代入元)の値のコンパイル時参照型 T(代入先)への代入は,次のとおり検査する。 クラスの規定については8.を,インタフェースについては9.を,配列については10.を参照のこと。 次のテストプログラムは,参照値についての代入変換を例示するが,注釈で記述するとおり,これは,優先順位規則に違反しているためにコンパイルに失敗する。この例を一つ前の例と比較することが望ましい。
public class Point { int x, y; }
public interface Colorable { void setColor(int color); }
public class ColoredPoint extends Point implements Colorable 
{
	int color;
	public void setColor(int color) { this.color = color; }
}
class Test {
	public static void main(String[] args) {
		Point p = new Point();
		ColoredPoint cp = new ColoredPoint();
		// Okay because ColoredPoint is a subclass of Point:
		p = cp;
		// Okay because ColoredPoint implements Colorable:
		Colorable c = cp;
		// The following cause compile-time errors because
		// we cannot be sure they will succeed, depending on
		// the run-time type of p; a run-time check will be
		// necessary for the needed narrowing conversion and
		// must be indicated by including a cast:
		cp = p;		// p might be neither a ColoredPoint
					// nor a subclass of ColoredPoint
		c = p;			// p might not implement Colorable
	}
}
配列オブジェクトの代入を含む例をもう一つ次に示す。

class Point { int x, y; }
class ColoredPoint extends Point { int color; }
class Test {
	public static void main(String[] args) {
		long[] veclong = new long[100];
		Object o = veclong;			// okay
		Long l = veclong;			// compile-time error
		short[] vecshort = veclong;	// compile-time error
		Point[] pvec = new Point[100];
		ColoredPoint[] cpvec = new ColoredPoint[100];
		pvec = cpvec;			// okay
		pvec[0] = new Point();		// okay at compile time,
							// but would throw an
							// exception at run time
		cpvec = pvec;			// compile-time error
	}
}
この例では,

cpvec = (ColoredPoint[])pvec;	// okay, but may throw an
					// exception at run time

5.3 メソッド呼出し変換

メソッド呼出し変換 (method invocation conversion) は,メソッド又はコンストラクタの呼出し(15.915.12)の各実引数値に適用する。実引数式の型は,対応する仮引数の型に変換しなければならない。メソッド呼出し文脈は,恒等変換(5.1.1), プリミティブ型拡大変換 (5.1.2),又は参照型拡大変換 (5.1.4)を可能とする。

実引数式の型がfloatもしくはdoubleならば,型変換の後に,値集合変換 (5.1.8) が適用される。

メソッド呼出し変換は,代入変換(5.2)の一部となる暗黙の整数定数の縮小変換を含まない。Javaの設計者達は,このような暗黙の縮小変換がオーバロードされたメソッドの照合解決過程(15.12.2)を複雑なものとするためと考えたからである。つまり,次の例はコンパイル時にエラーを引き起こす。
class Test {
	static int m(byte a, int b) { return a+b; }
	static int m(short a, short b) { return a-b; }
	public static void main(String[] args) {
		System.out.println(m(12, 2));		// compile-time error
	}
}
これは変数リテラル12及び2は,型intを持つのでいずれのメソッドm(15.12.2)の規則のもとでは一致しないからである。整数定数の暗黙縮小を含む言語では,この例のような場合を解決する追加規則を必要とする。

5.4 文字列変換

文字列変換は,実引数の一方が String のとき,二項演算子 + のオペランドにだけ適用する。この場合,+ の他方の実引数を String に変換し,二つの文字列の連結である新しい String+ の結果となる。文字列変換は,文字列の連結演算子 + (15.18.1)の記述で詳細に規定する。

5.5 キャスト変換

キャスト変換 (casting conversion) は,キャスト演算子(15.16)のオペランドに適用する。このときオペランド式の型は,キャスト演算子で明示的に名前を与えた型に変換しなければならない。キャストの文脈では,恒等変換(5.1.1),プリミティブ型の拡大変換(5.1.2),プリミティブ型の縮小変換(5.1.3),参照型の拡大変換(5.1.4),又は,参照型の縮小変換(5.1.5)の利用を可能とする。従って,キャスト変換は,代入変換又は,メソッド呼出し変換よりも包括的とする。つまり,キャストは文字列変換以外の任意の変換が許される。

値集合変換(5.1.8)は,型変換の後に適用される。

コンパイル時に不正と証明されるキャストもある。このようなキャストは,コンパイル時エラーを発生させる。

プリミティブ型の値は,型が同じならば恒等変換によって,そうでないときにはプリミティブ型の拡大変換又はプリミティブ型の縮小変換によって,他のプリミティブ型にキャストできる。

プリミティブ型の値を,キャスト変換によって参照型にキャストすることはできないし,参照型の値をプリミティブ型にキャストすることもできない。

残りの場合は,参照型間の変換に関係する。コンパイル時参照型 S (変換元)の値から,コンパイル時参照型 T (変換先)へのキャスト変換のコンパイル時正当性検査に関する詳細規則は次のとおりとする。

クラスの詳しい規定は,8を, インタフェースは,9を,そして,配列は10を参照のこと。

参照型へのキャストがコンパイル時エラーでなければ,次の二つの場合が存在する。

実行時例外が投げられる場合,それは,ClassCastException とする。

5.2の例と同様の参照型へのキャスト変換の例を次に示す。

public class Point { int x, y; }
public interface Colorable { void setColor(int color); }
public class ColoredPoint extends Point implements Colorable 
{
	int color;
	public void setColor(int color) { this.color = color; }
}
final class EndPoint extends Point { }
class Test {
	public static void main(String[] args) {
		Point p = new Point();
		ColoredPoint cp = new ColoredPoint();
		Colorable c;

		// The following may cause errors at run time because
		// we cannot be sure they will succeed; this possibility
		// is suggested by the casts:
		cp = (ColoredPoint)p;	// p might not reference an
						// object which is a ColoredPoint
						// or a subclass of ColoredPoint
		c = (Colorable)p;		// p might not be Colorable

		// The following are incorrect at compile time because
		// they can never succeed as explained in the text:
		Long l = (Long)p;		// compile-time error #1
		EndPoint e = new EndPoint();
		c = (Colorable)e;		// compile-time error #2
	}
}
ここで,クラス型 Long 及び Point は関係しない(つまり,これらは同じではないし,相手の下位クラスでもない)ために,最初のコンパイル時エラーが生じる。従って,これらの間のキャストは,常に失敗する。

EndPoint の変数はインタフェース Colorable を実装する値を参照できないために,第二のコンパイル時エラーを生じる。これは,EndPointfinal な型であって,final な型の変数は常にコンパイル時の型と同じ実行時の型の値を保持することによる。そこで,変数 e の実行時の型は正確に型 EndPoint でなければならず,型 EndPointColorableを実装しない。

次に,配列(10.)を含む例を示す。

class Point {
	int x, y;
	Point(int x, int y) { this.x = x; this.y = y; }
	public String toString() { return "("+x+","+y+")"; }
}
public interface Colorable { void setColor(int color); }
public class ColoredPoint extends Point implements Colorable 
{
	int color;
	ColoredPoint(int x, int y, int color) {
		super(x, y); setColor(color);
	}
	public void setColor(int color) { this.color = color; }
	public String toString() {
		return super.toString() + "@" + color;
	}
}
class Test {
	public static void main(String[] args) {
		Point[] pa = new ColoredPoint[4];
		pa[0] = new ColoredPoint(2, 2, 12);
		pa[1] = new ColoredPoint(4, 5, 24);
		ColoredPoint[] cpa = (ColoredPoint[])pa;
		System.out.print("cpa: {");
		for (int i = 0; i < cpa.length; i++)
			System.out.print((i == 0 ? " " : ", ") + cpa[i]);
		System.out.println(" }");
	}
}
この例は,エラーなしにコンパイルされ,次の出力を生成する。

cpa: { (2,2)@12, (4,5)@24, null, null }

次の例は,コンパイルのためにキャストを使用しているが,型に互換性がないために実行時に例外を投げる。
public class Point { int x, y; }
public interface Colorable { void setColor(int color); }
public class ColoredPoint extends Point implements Colorable 
{
	int color;
	public void setColor(int color) { this.color = color; }
}
class Test {
	public static void main(String[] args) {
		Point[] pa = new Point[100];
		// The following line will throw a ClassCastException:
		ColoredPoint[] cpa = (ColoredPoint[])pa;
		System.out.println(cpa[0]);
		int[] shortvec = new int[2];
		Object o = shortvec;
		// The following line will throw a ClassCastException:
		Colorable c = (Colorable)o;
		c.setColor(0);
	}

}

5.6 数値昇格

数値昇格 (numeric promotion) は,算術演算のオペランドに対して適用する。数値昇格の文脈では,恒等変換(5.1.1),又はプリミティブ型の拡大変換(5.1.2)が使用できる。

数値昇格は,数値演算子のオペランドを共通の型に変換するために使用する。演算が実行可能となるように,数値昇格には,単項数値昇格(5.6.1)と二項数値昇格(5.6.2)の二種類が存在する。C言語での類似の変換は,"通常の単項変換" 及び "通常の二項変換"と呼ぶ。

数値昇格は,Javaプログラム言語の全体的な特徴ではなく,組込み演算の特性である。

5.6.1 単項数値昇格

演算子には, 単項数値昇格 (unary numeric promotion) を単一オペランドに適用するものがあり,次のように数値型の値を生成しなければならない。

いずれの場合でも,その次に値集合変換(5.1.8) が適用される。

単項数値昇格は,次の状況の式に関して実行する。

class Test {
	public static void main(String[] args) {
		byte b = 2;
		int a[] = new int[b];	// dimension expression promotion
		char c = '\u0001';
		a[c] = 1;			// index expression promotion
		a[0] = -c;			// unary - promotion
		System.out.println("a: " + a[0] + "," + a[1]);
		b = -1;
		int i = ~b;			// bitwise complement promotion
		System.out.println("~0x" + Integer.toHexString(b)
			         + "==0x" + Integer.toHexString(i));
		i = b << 4L;			// shift promotion (left operand)
		System.out.println("0x" + Integer.toHexString(b)
			         + "<<4L==0x" + Integer.toHexString(i));
	}
}
このテストプログラムは,次の出力を生成する。

a: -1,1
~0xffffffff==0x0
0xffffffff<<4L==0xfffffff0

5.6.2 二項数値昇格

ある演算子が 二項数値昇格 (binary numeric promotion) をオペランドの対に適用するときは,個々のオペランドが,数値型の値を表さなければならないが,必要に応じてオペランド変換するための拡大変換(5.1.2)を用いて,順番に次の規則を適用する。

型変換の後,必要ならば,値集合変換(5.1.8)が各オペランドに適用される。

二項数値昇格は,特定の演算子のオペランドに関して実行する。

二項数値昇格の例は,上記の5.1に存在する。ここでは別の例を示す。

class Test {
	public static void main(String[] args) {
		int i = 0;
		float f = 1.0f;
		double d = 2.0;
		// First int*float is promoted to float*float, then
		// float==double is promoted to double==double:
		if (i * f == d)
			System.out.println("oops");
		// A char&byte is promoted to int&int:
		byte b = 0x1f;
		char c = 'G';
		int control = c & b;
		System.out.println(Integer.toHexString(control));
		// Here int:float is promoted to float:float:
		f = (b==0) ? i : 4.0f;
		System.out.println(1.0/f);
	}
}
これは次の出力を生成する。

7
0.25
この例は,ASCII文字 G の下位5ビットを除く全体にゼロのマスクをかけることによって,この文字をASCII文字の control-G (BEL)に変換する。7 は,この制御文字の数値である。

目次 | | | 索引 Java言語規定
第2版