if
文(14.8)内の式が
boolean
以外の型をもてば,コンパイル時エラーが発生する。文脈によっては,式の型が受理可能な場合もある。Java言語では,プログラマに明示的型変換を要求するかわりに,指定された式の型から,式をとりまく文脈にとって受理可能な型への暗黙的な
変換(conversion) を実行することを図る。
型 S から型 T への特定の変換によって,型 S の式を,あたかも型 T をもつかのようにコンパイル時に扱うことができる。この変換の正当性を検査する実行時動作,又は式の実行時の値を新しい型 T にとって適切な形式に翻訳する実行時動作が,必要となる場合もある。その例を次に示す。
Object
(20.1)から型
Thread
(20.20)への変換は,実行時の値が実際にクラス
Thread
又はそのサブクラスのインスタンスであることを確認するための実行時検査を要求する。そうでないときには例外が投げられる。
Thread
から型 Object
への変換は,実行時動作を要求しない。Thread
は Object
のサブクラスなので,型
Thread
の式が生成するいかなる参照も型 Object
の正当な参照値となる。
int
から型 long
への変換は,32ビット整数値の64ビット
long
表現への実行時符号拡張を要求する。いかなる情報も失われない。
double
から型 long
への変換は,64ビット浮動小数点の値から64ビット整数表現への自明でない翻訳を要求する。実際の実行時の値によっては,情報が失われることがある。
Java式の変換が発生可能な 変換の文脈(conversion context) には5種類ある。個々の文脈で,可能な変換を定めた。"変換" という用語は,文脈に対して特定の変換を選択する過程を記述するためにも使用する。例えば,メソッド呼出しで実引数の式が,"メソッド呼出し変換" に従う,というが,これはメソッド呼出し実引数の文脈に対する規則によって,その式に合った特定の変換を暗黙的に選択することを意味する。
変換文脈の中には,+
,*
などの数値演算子のオペランドとなる数値がある。この数値オペランドの変換過程を 数値昇格(numeric promotion)
と呼ぶ。二項演算子の場合は,一方のオペランドに対する変換の選択が,他方のオペランド式の型に部分的に依存する可能性がある。
5.では,最初に,文字列の連結演算子 +
に対して許される
String
への特殊な変換を含む,変換の六つの大分類 (5.1)を規定する。次に,五つの変換文脈を規定する。
String
へと変換可能とする。
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
型 boolean
を含む唯一許される変換は,boolean
から
boolean
への恒等変換とする。
byte
から
short
,int
,long
,float
,又は
double
への変換。
short
から
int
,long
,float
,又は double
への変換。
char
から
int
,long
,float
,又は double
への変換。
int
から long
,float
,又は
double
への変換。
long
から float
又は double
への変換。
float
から double
への変換。 float
から型 double
への拡大変換は,いかなる情報も失うことはない。つまり,数値を正確に保存する。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桁の有効数字の精度がないために,情報が失われたことを示している。
byte
から char
への変換。
short
から byte
又は char
への変換。
char
から byte
又は short
への変換。
int
から byte
,short
又は
char
への変換。
long
から
byte
,short
,char
又は int
への変換。
float
から
byte
,short
,char
,int
又は
long
への変換。
double
から
byte
,short
,char
,int
,long
又は float
への変換。 符号付き整数の整数型 T への縮小変換は,単に n 個,最小位ビット以外のすべての情報を捨てる。ここで,n は,型 T を表現するのに使用するビット数とする。数値の大きさに関する情報の損失の可能性に加えて,結果値の符号が,入力値の符号と異なってしまうことがある。
同様にして,文字型から整数型 T への縮小変換は,単に n 個,最小位ビット以外のすべての情報を捨てる。ここで n は,型 T を表現するのに使用するビット数とする。数値の大きさに関する情報の損失の可能性に加えて,文字が16ビットの符号なし整数値を表わすにもかかわらず,結果値が,負の数になることがある。
浮動小数点数から整数型 T への縮小変換は,二つの段階を踏む。
long
ならば long
に変換し,T が byte
,short
,char
又は
int
ならば int
に変換する。
int
又は
long
の 0
とする。
long
であって,この整数値が long
で表現できれば,第一段階の結果は, long
の値 V とする。
int
として表現できれば,第一段階の結果は,int
の値 V とする。 int
又は long
ならば,変換の結果は,第一段階の結果とする。
byte
,char
又は short
ならば,変換の結果は,第一段階の結果の型 T への縮小変換(5.1.3)の結果とする。 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
char
,int
及び long
に対する結果は,その型の最小及び最大表現可能値を生成する。
byte
及び short
に対する結果は,符号及び数値の大きさに関する情報を失い,精度も失う。この結果は,int
の最小数及び最大数の下位ビットを調べることにより理解できる。 最小の int
は16進で
0x80000000
であって,最大の int
は 0x7fffffff
である。これから,short
の結果が値の下位16ビット,つまり 0x0000
及び
0xffff
となることが説明される。また char
の結果もまた,これらの値の下位16ビット,つまり
'\u0000'
及び '\uffff'
となることで説明される。更に byte
の結果が,これらの値の下位8ビット,つまり 0x00
及び 0xff
となることで説明される。
double
から float
への縮小変換は, IEEE
754に準拠して実行される。この結果は, IEEE 754の直近への丸めモードを使用して正確に丸められる。float
として表現するには小さすぎる値は,正又は負のゼロに変換する。float
として表現するには大きすぎる値は,(正又は負の)無限大に変換する。double
NaN は,常に
float
NaN に変換する。
オーバフロー,アンダフロー又はその他の情報の損失が生ずる可能性があるという事実にもかかわらず,プリミティブ型間の縮小変換は,実行時例外(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
Object
への拡大変換が存在する)。
Object
への変換。
Object
への変換。
Cloneable
への変換。
[]
から任意の TC[]
への変換。 クラスの詳細な規定については 8を,インタフェースについては9を,配列については10を参照のこと。
Object
から任意の他のクラス型への縮小変換が存在する。)
Object
から任意のインタフェース型への縮小変換が存在する。)
Object
から任意の配列型への変換。
Object
から任意のインタフェース型への変換。
final
でない任意のクラス型 T への変換。
final
な任意のクラス型 T
への変換。ただし,T は J を実装する。
[]
から配列型 TC []
への変換。ただし,
SC 及び TC は参照型とし,SC から TC への縮小変換が存在する。 ClassCastException
が投げられる。
String
への文字列変換が存在する。
boolean
への変換は許さない。
boolean
からの変換は許さない。
final
なクラス型 Sが,インタフェース型 K を実装しなければ,
S から K への変換は許さない。
Object
でなければ,S から任意の配列型への変換は許さない。
final
なクラス型 Tが,インタフェース型 J
を実装しなければ,文字列変換以外のJ から T への変換は許さない。
Object
又は String
以外の任意のクラス型への任意の配列型からの変換は許さない。
Cloneable
への変換を除いて許さない。
[]
から配列型 TC []
への変換は許さない。 式の型が,代入文脈で許される変換によって変数の型へ変換できなければ,コンパイル時エラーが発生する。
式の型が代入変換によって変数の型に変換可能ならば,その式(又はその式の値)は,その変数に対して 代入可能(assignable to) 又は等価だが,式の型は変数の型と 代入互換(assignment compatible with) とする。
代入変換は,例外を発生しない。(しかし,配列の要素を含む特別な場合には,代入が例外を生じることがあるので注意すること。10.10及び15.25.1を参照のこと。)
コンパイル時の定数の縮小とは,次のようなコードを許すことを意味する。
byte theAnswer = 42;縮小がなければ,整数リテラル
42
は型 int
をもつという事実は,byte
へのキャストを要求することになる。
byte theAnswer = (byte)42;プリミティブ型の値は,参照型の変数に代入してはならない。これを実行しようとすると,コンパイル時エラーを生じる。型
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 i=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; }コンパイル時参照型 S(代入元)の値のコンパイル時参照型 T(代入先)への代入は,次のように検査する。
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
}
}
Object
でなければならない。そうでないときには,コンパイル時エラーが発生する。
[]
,つまり型 SC の構成要素をもつ配列の場合。
次のテストプログラムは,参照値についての代入変換を例示するが,注釈で記述するとおり,これは,優先順位規則に違反しているためにコンパイルに失敗する。この例を一つ前の例と比較することが望ましい。
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 } }
Long
は Object
以外のクラス型(20.8)だから,veclong
の値を Long
の変数に代入することはできない。配列は,互換性のある配列型の変数又は型
Object
の変数にだけ代入できる。
veclong
の値は,プリミティブ型の配列であって,short
及び long
は同じプリミティブ型ではないから, vecshort
には代入できない。
ColoredPoint
の式の値となることが可能な任意の参照は,型 Point
の変数の値となることが可能だから,cpvec
の値は pvec
に代入できる。それに続く,new
Point
の
pvec
の構成要素への代入は,(このプログラムをコンパイルできるように別途修正したとしても,)例外ArrayStoreException
を投げる。 その理由は,配列ColoredPoint
は,構成要素の値として型 Point
のインスタンスをもつことができないからとなる。
ColoredPoint
の式の値となることが可能な参照が必ずしもすべて型 Point
の変数の正しい値であるとは限らないから,pvec
の値は, cpvec
に代入できない。pvec
の実行時の値が Point[]
のインスタンスへの参照であって,cpvec
への代入が許されていれば,cpvec
の構成要素への単純参照,例えば cpvec[0]
は Point
を返すことができるが,Point
は ColoredPoint
ではない。したがって,そのような代入を許すことは,型システムの破壊を許すことになる。pvec
が
ColoredPoint[]
を参照するのを保証するために,キャストを使用することができる(5.4,15.15)。
cpvec = (ColoredPoint[])pvec; // okay, but may throw an // exception at run time
メソッド呼出し変換は,オーバロードされたメソッドの照合解決過程(15.11.2)が複雑になるため,代入変換(5.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.11.2)の規則のもとでは一致しないからである。整数定数の暗黙縮小を含む言語では,この例のような場合を解決する追加規則を必要とする。
String
のとき,二項演算子 +
のオペランドにだけ適用する。この場合,+
の他方の実引数を
String
に変換し,二つの文字列の連結である新しい String
が +
の結果となる。文字列変換は,文字列の連結演算子 +
(15.17.1)の記述で詳細に規定する。
コンパイル時に不正と証明されるキャストもある。このようなキャストは,コンパイル時エラーを生じる。
プリミティブ型の値は,型が同じならば恒等変換によって,そうでないときにはプリミティブ型の拡大変換又はプリミティブ型の縮小変換によって,他のプリミティブ型にキャストできる。
プリミティブ型の値を,キャスト変換によって参照型にキャストすることはできないし,参照型の値をプリミティブ型にキャストすることもできない。
残りの場合は,参照型間の変換に関係する。コンパイル時参照型 S(変換元)の値から,コンパイル時参照型 T(変換先)へのキャスト変換の,コンパイル時正当性検査に関する詳細規則は,次のとおりとする。
final
クラス(8.1.2)でなければ,キャストは,コンパイル時には常に正しい(その理由は,S
が T を実装していなくとも, S のサブクラスが実装しているかもしれないからである)。
final
クラス(8.1.2)ならば,S は T
を実装しなければならない,そうでないときには,コンパイル時エラーが発生する。 Object
でなければならない。そうでないときには,コンパイル時エラーが発生する。 final
(8.1.2)でないクラス型ならば,キャストはコンパイル時には常に正しい(その理由は,T
が S を実装していなくとも,T のサブクラスが実装しているからである)。
final
(8.1.2)なクラス型ならば,T は S
を実装しなければならない。そうでないときには,コンパイル時エラーが発生するする。
[]
,つまり型 SC を構成要素にもつ配列の場合。
参照型へのキャストがコンパイル時エラーでなければ,次の二つの場合が存在する。
null
ならば,キャストは可能となる。それ以外の場合は,R を実行時の参照値によって参照されるオブジェクトのクラスとし,T
をそのキャスト演算子によって名前を与えられた型とする。キャスト変換は,実行時にクラス R が 型 T
と代入互換であることを,5.2で規定されたアルゴリズムを使って,ただしそこで規定しているコンパイル時の型
S をクラス R
に置き換えて使用して,検査しなければならない。(これらの規則を任意の与えられたキャストに対して最初に適用するときには,R
はインタフェースになることはないが,これらの規則を再帰的に適用すれば,R
はインタフェースなることがある点に注意すること。その理由は,実行時の参照値が,その要素の型がインタフェース型である配列を参照することがあるからとする。)この修正されたアルゴリズムを次に示す。
Object
(4.3.2,20.1)でなければならない。そうでないときには,実行時例外が投げられる。
[]
を表わすクラス,つまりRCを構成要素とする配列の場合。
ClassCastException
(11.5.1.1,20.22)とする。
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
を実装する値を参照できないために,第二のコンパイル時エラーが生じる。これは,EndPoint
が
final
な型であって,final
な型の変数は常にコンパイル時の型と同じ実行時の型の値を保持することによる。そこで変数 e
の実行時の型は正確に型
EndPoint
でなければならず,型 EndPoint
は Colorable
を実装しない。
次に,配列(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.1)及び二項数値昇格(5.6.2)の二種類が存在する。C言語での類似の変換は,"通常単項変換"及び"通常二項変換"と呼ぶ。
数値昇格は,Javaの全体的な特徴ではなく,組込み演算の特性である。
byte
,short
又は char
をもてば,単項数値昇格はこれを拡大変換(5.1.2)によって型
int
の値に昇格する。
+
(15.14.3)及び減算
-
(15.14.4)のオペランド。
~
(15.14.5)のオペランド。
>>
,>>>
,及び
<<
(15.18)の各々の各オペランド。
シフト幅(右オペランド)が型long
でも,シフトされる値(左オペランド)は型 long
に昇格しない。 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
double
ならば,他方を double
に変換する。
float
ならば,他方を float
に変換する。
long
ならば,他方を long
に変換する。
int
に変換する。
*
,/
及び %
(15.16)。
+
及び減算演算子 -
(15.17.2)。
<
,<=
,>
及び
>=
(15.19.1)。
==
及び !=
(15.20.1)。
&
,^
及び |
(15.21.1)。
? :
(15.24)。
class Test { public static void main(String[] args) { int i = 0; float f = 1.0f; double d = 2.0;これは,次の出力を生成する。
// First i*f 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));
// A int:float promoted to float:float: f = (b==0) ? f : 4.0f; System.out.println(1.0/f);
}
}
7 0.25この例は,ASCII文字
G
の下位5ビットを除く全体にゼロのマスクをかけることによって,この文字をASCII文字の “control-G (BEL)”
に変換する。7
は,この制御文字の数値である。