Spec-Zone .ru
спецификации, руководства, описания, API
|
ГЛАВА 5
У каждого выражения Java есть тип, который может быть выведен из структуры выражения и типов литералов, переменных, и методов, упомянутых в выражении. Возможно, однако, записать выражение в контексте, где тип выражения не является соответствующим. В некоторых случаях это приводит к ошибке во время компиляции; например, если выражение в if
у оператора (§14.8) есть любой тип кроме boolean
, ошибка времени компиляции происходит. В других случаях контекст может быть в состоянии принять тип, который связывается с типом выражения; как удобство, вместо того, чтобы требовать, чтобы программист указал на преобразование типов явно, язык Java выполняет неявное преобразование из типа выражения к типу, приемлемому для его окружающего контекста.
Определенное преобразование от типа 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-разрядного целочисленного представления. В зависимости от фактического значения времени выполнения может быть потеряна информация.
Один контекст преобразования является операндом числового оператора такой как +
или *
. Процесс преобразования для таких операндов вызывают числовым продвижением. Продвижение является особенным в этом, в случае бинарных операторов, преобразование, выбранное для одного операнда, может зависеть частично от типа другого выражения операнда.
Эта глава сначала описывает шесть категорий преобразований (§5.1), включая специальные преобразования в String
учтенный оператор конкатенации строк +
. Затем пять контекстов преобразования описываются:
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
или a long
значение к float
, или a long
значение к double
, может привести к потере точности - то есть, результат может потерять некоторые из младших значащих битов значения. В этом случае получающееся значение с плавающей точкой будет правильно округленной версией целочисленного значения, используя режим раунда-к-самому-близкому IEEE 754 (§4.2.4).Расширяющееся преобразование целого числа со знаком оценивает целочисленному типу T, просто подписываются - расширяет two's-дополнительное представление целочисленного значения, чтобы заполнить более широкий формат. Расширяющееся преобразование символа к целочисленному типу 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
не точны к девяти существенным цифрам. 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
, если T long
, или к int
, если T byte
, short
, char
, или int
, следующим образом: int
или long
0
.
long
, и это целочисленное значение может быть представлено как a long
, тогда результат первого шага long
значение V.
int
, тогда результат первого шага int
значение V. int
или long
.
int
или long
. 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
в шестнадцатеричном, 0x80000000
, и максимум int
0x7fffffff
. Это объясняет short
результаты, которые составляют низкие 16 битов этих значений, а именно, 0x0000
и 0xffff
; это объясняет char
результаты, которые также составляют низкие 16 битов этих значений, а именно, '\u0000'
и '\uffff'
; и это объясняет byte
результаты, которые составляют низкие 8 битов этих значений, а именно, 0x00
и 0xff
.
Сужающееся преобразование из double
к float
ведет себя в соответствии с IEEE 754. Результат правильно округляется, используя режим раунда-к-самому-близкому IEEE 754. Значение, слишком маленькое, чтобы быть представленным как a float
преобразовывается в положительный или отрицательный нуль; значение, слишком большое, чтобы быть представленным как a float
преобразовывается в (положительный или отрицательный) бесконечность. A double
НЭН всегда преобразовывается в a float
НЭН.
Несмотря на то, что переполнение, потеря значимости, или другая потеря информации могут произойти, сужая преобразования среди типов примитивов никогда не приводит к исключению на этапе выполнения (§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[]
, при условии, что SC и TC являются ссылочными типами и есть расширяющееся преобразование от SC до TC. См. §8 для подробных спецификаций для классов, §9 для интерфейсов, и §10 для массивов.
Object
к любому другому типу класса.)
Object
к любому интерфейсному типу.)
Object
к любому типу массива.
Object
к любому интерфейсному типу.
final
.
final
, при условии, что T реализует J.
[]
любому массиву вводят TC[]
, при условии, что SC и TC являются ссылочными типами и есть сужающееся преобразование от SC до TC. ClassCastException
бросается. String
от любого типа, включая нулевой тип. boolean
кроме преобразования идентификационных данных.
boolean
кроме преобразования идентификационных данных и преобразования строк.
final
и не реализует K.
Object
.
final
и не реализует J.
Object
или String
.
Cloneable
, который реализуется всеми массивами.
[]
выстраивать TC типа[]
если нет никакого разрешенного преобразования кроме преобразования строк от SC до TC.
int
.
byte
, short
, или char
.
Если тип выражения может быть преобразован в тип переменная преобразованием присвоения, мы говорим, что выражение (или его значение) присваиваемо переменной или, эквивалентно, что тип выражения является присвоением, совместимым с типом переменной.
Преобразование присвоения никогда не вызывает исключение. (Отметьте, однако, что присвоение может привести к исключению в массиве включения особого случая, элементы - видят §10.10 и §15.25.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 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 типа: Object
, или ошибка времени компиляции происходит.
Cloneable
, единственный интерфейс реализуется массивами.
[]
, то есть, массив компонентов TC типа, затем ошибка времени компиляции происходит, если одно из следующего не является истиной:
Следующая тестовая программа иллюстрирует преобразования присвоения на ссылочных значениях, но не в состоянии скомпилировать, потому что она нарушает предыдущие правила, как описано в его комментариях. Этот пример должен быть по сравнению с предыдущим.
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 } }
veclong
не может быть присвоен a Long
переменная, потому что Long
тип класса (§20.8) кроме Object
. Массив может быть присвоен только переменной совместимого типа массива, или к переменной типа Object
.
veclong
не может быть присвоен vecshort
, потому что они - массивы типа примитива, и short
и long
не тот же самый тип примитива.
cpvec
может быть присвоен pvec
,
потому что любая ссылка, которая могла быть значением выражения типа ColoredPoint
может быть значение переменной типа Point
. Последующее присвоение нового Point
к компоненту pvec
тогда бросил бы ArrayStoreException
(если программа была иначе исправлена так, чтобы она могла быть скомпилирована), потому что a ColoredPoint
у массива не может быть экземпляра Point
как значение компонента.
pvec
не может быть присвоен cpvec
,
потому что не каждая ссылка, которая могла быть значением выражения типа ColoredPoint
может правильно быть значение переменной типа Point
. Если значение pvec
во время выполнения была ссылка на экземпляр Point[]
, и присвоение на cpvec
были позволены, простая ссылка на компонент cpvec
, Скажем, cpvec[0]
, мог возвратить a Point
, и a Point
не a ColoredPoint
. Таким образом позволить такое присвоение позволило бы нарушение системы типов. Бросок может использоваться (§5.4, §15.15), чтобы гарантировать это pvec
ссылки a ColoredPoint[]
: cpvec = (ColoredPoint[])pvec; // okay, but may throw an // exception at run time
Преобразования вызова метода определенно не включают неявное сужение целочисленных констант, которое является частью преобразования присвоения (§5.2). Разработчики Java чувствовали, что включая эти неявные преобразования сужения добавит дополнительную сложность к перегруженному методу, соответствующему процесс разрешения (§15.11.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). Язык, который включал неявное сужение целочисленных констант, будет нуждаться в дополнительных правилах разрешить случаи как этот пример. +
оператор, когда одним из параметров является a String
. В этом единственном особом случае, другом параметре +
преобразовывается в a 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 типа: Object
, тогда ошибка времени компиляции происходит (потому что Object
единственный тип класса, которому массивы могут быть присвоены).
Cloneable
, единственный интерфейс реализуется массивами.
[]
, то есть, массив компонентов TC типа, затем ошибка времени компиляции происходит, если одно из следующего не является истиной:
Если бросок к ссылочному типу не является ошибкой времени компиляции, есть два случая:
null
, тогда бросок позволяется. Иначе, позвольте R быть классом объекта, упомянутого ссылочным значением времени выполнения, и позволять T быть типом, названным в операторе броска. Преобразование броска должно проверить во время выполнения, что класс R является присвоением, совместимым с типом T, используя алгоритм, определенный в §5.2, но используя класс R вместо типа S времени компиляции как определено там. (Отметьте, что R не может быть интерфейсом, когда эти правила сначала применяются для любого данного броска, но R может быть интерфейсом, если правила применяются рекурсивно, потому что ссылочное значение времени выполнения обращается к массиву, тип элемента которого является интерфейсным типом.) Этот измененный алгоритм показывают здесь: Object
(§4.3.2, §20.1), или исключение на этапе выполнения бросается.
[]
- то есть, массив компонентов RC типа:
Object
(§4.3.2, §20.1), или исключение на этапе выполнения бросается.
Cloneable
, единственный интерфейс, реализованный массивами (этот случай мог уменьшиться мимо времени компиляции, проверяя, была ли, например, ссылка на массив сохранена в переменной типа Object
).
[]
, то есть, массив компонентов TC типа, затем исключение на этапе выполнения бросается, если одно из следующего не является истиной:
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
a final
введите, и переменная a 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
, унарное числовое продвижение продвигает это значение типа int
расширяющимся преобразованием (§5.1.2).
+
(§15.14.3) и минус -
(§15.14.4)
~
(§15.14.5)
>>
, >>>
, и <<
(§15.18), так, чтобы a 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
к г управления ASCII (BEL), маскируя от всех кроме низких 5 битов символа. 7
числовое значение этого управляющего символа.
Содержание | Предыдущий | Следующий | Индекс
Спецификация языка Java (HTML, сгенерированный Блинчиком "сюзет" Pelouch 24 февраля 1998)
Авторское право © Sun Microsystems, Inc 1996 года. Все права защищены
Пожалуйста, отправьте любые комментарии или исправления к doug.kramer@sun.com