Movatterモバイル変換


[0]ホーム

URL:


Oracle Logo

Java SE >Java SE Specifications >Java Language Specification

Chapter 5. Conversions and Contexts
Prev   Next

Chapter 5. Conversions and Contexts

Table of Contents

5.1. Kinds of Conversion
5.1.1. Identity Conversion
5.1.2. Widening Primitive Conversion
5.1.3. Narrowing Primitive Conversion
5.1.4. Widening and Narrowing Primitive Conversion
5.1.5. Widening Reference Conversion
5.1.6. Narrowing Reference Conversion
5.1.6.1. Allowed Narrowing Reference Conversion
5.1.6.2. Checked and Unchecked Narrowing Reference Conversions
5.1.6.3. Narrowing Reference Conversions at Run Time
5.1.7. Boxing Conversion
5.1.8. Unboxing Conversion
5.1.9. Unchecked Conversion
5.1.10. Capture Conversion
5.1.11. String Conversion
5.1.12. Forbidden Conversions
5.2. Assignment Contexts
5.3. Invocation Contexts
5.4. String Contexts
5.5. Casting Contexts
5.6. Numeric Contexts
5.7. Testing Contexts

Every expression written in the Java programming language either produces no result (§15.1) or has a type that can be deduced at compile time (§15.3). When an expression appears in most contexts, it must becompatible with a type expected in that context; this type is called thetarget type. For convenience, compatibility of an expression with its surrounding context is facilitated in two ways:

If neither strategy is able to produce the appropriate type, a compile-time error occurs.

The rules determining whether an expression is a poly expression, and if so, its type and compatibility in a particular context, vary depending on the kind of context and the form of the expression. In addition to influencing the type of the expression, the target type may in some cases influence the run time behavior of the expression in order to produce a value of the appropriate type.

Similarly, the rules determining whether a target type allows an implicit conversion vary depending on the kind of context, the type of the expression, and, in one special case, the value of a constant expression (§15.29). A conversion from typeS to typeT allows an expression of typeS to be treated at compile time as if it had typeT instead. In some cases this will require a corresponding action at run time to check the validity of the conversion or to translate the run-time value of the expression into a form appropriate for the new typeT.

Example 5.0-1. Conversions at Compile Time and Run Time

  • A conversion from typeObject to typeThread requires a run-time check to make sure that the run-time value is actually an instance of classThread or one of its subclasses; if it is not, an exception is thrown.

  • A conversion from typeThread to typeObject requires no run-time action;Thread is a subclass ofObject, so any reference produced by an expression of typeThread is a valid reference value of typeObject.

  • A conversion from typeint to typelong requires run-time sign-extension of a 32-bit integer value to the 64-bitlong representation. No information is lost.

  • A conversion from typedouble to typelong requires a non-trivial translation from a 64-bit floating-point value to the 64-bit integer representation. Depending on the actual run-time value, information may be lost.


The conversions possible in the Java programming language are grouped into several broad categories:

There are seven kinds ofconversion contexts in which poly expressions may be influenced by context or implicit conversions may occur. Each kind of context has different rules for poly expression typing and allows conversions in some of the categories above but not others. The contexts are:

The term "conversion" is also used to describe, without being specific, any conversions allowed in a particular context. For example, we say that an expression that is the initializer of a local variable is subject to "assignment conversion", meaning that a specific conversion will be implicitly chosen for that expression according to the rules for the assignment context. As another example, we say that an expression undergoes "casting conversion" to mean that the expression's type will be converted as permitted in a casting context.

Example 5.0-2. Conversions In Various Contexts

class Test {    public static void main(String[] args) {        // Casting conversion (5.5) 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);        // 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);    }}

This program produces the output:

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

5.1. Kinds of Conversion

Specific type conversions in the Java programming language are divided into 12 kinds.

5.1.1. Identity Conversion

A conversion from a type to that same type is permitted for any type.

This may seem trivial, but it has two practical consequences. First, it is always permitted for an expression to have the desired type to begin with, thus allowing the simply stated rule that every expression is subject to conversion, if only a trivial identity conversion. Second, it implies that it is permitted for a program to include redundant cast operators for the sake of clarity.

5.1.2. Widening Primitive Conversion

19 specific conversions on primitive types are called thewidening primitive conversions:

  • byte toshort,int,long,float, ordouble

  • short toint,long,float, ordouble

  • char toint,long,float, ordouble

  • int tolong,float, ordouble

  • long tofloat ordouble

  • float todouble

A widening primitive conversion does not lose information about the overall magnitude of a numeric value in the following cases, where the numeric value is preserved exactly:

  • from an integral type to another integral type

  • frombyte,short, orchar to a floating-point type

  • fromint todouble

  • fromfloat todouble

A widening primitive conversion fromint tofloat, or fromlong tofloat, or fromlong todouble, may result inloss of precision, that is, the result may lose some of the least significant bits of the value. In this case, the resulting floating-point value will be a correctly rounded version of the integer value, using the round to nearest rounding policy (§15.4).

A widening conversion of a signed integer value to an integral typeT simply sign-extends the two's-complement representation of the integer value to fill the wider format.

A widening conversion of achar to an integral typeT zero-extends the representation of thechar value to fill the wider format.

A widening conversion fromint tofloat, or fromlong tofloat, or fromint todouble, or fromlong todouble occurs as determined by the rules of IEEE 754 for converting from an integer format to a binary floating-point format.

A widening conversion fromfloat todouble occurs as determined by the rules of IEEE 754 for converting between binary floating-point formats.

Despite the fact that loss of precision may occur, a widening primitive conversion never results in a run-time exception (§11.1.1).

Example 5.1.2-1. Widening Primitive Conversion

class Test {    public static void main(String[] args) {        int big = 1234567890;        float approx = big;        System.out.println(big - (int)approx);    }}

This program prints:

-46

thus indicating that information was lost during the conversion from typeint to typefloat because values of typefloat are not precise to nine significant digits.


5.1.3. Narrowing Primitive Conversion

22 specific conversions on primitive types are called thenarrowing primitive conversions:

  • short tobyte orchar

  • char tobyte orshort

  • int tobyte,short, orchar

  • long tobyte,short,char, orint

  • float tobyte,short,char,int, orlong

  • double tobyte,short,char,int,long, orfloat

A narrowing primitive conversion may lose information about the overall magnitude of a numeric value, and may also lose precision and range.

A narrowing conversion of a signed integer to an integral typeT simply discards all but then lowest order bits, wheren is the number of bits used to represent typeT. In addition to a possible loss of information about the magnitude of the numeric value, this may cause the sign of the resulting value to differ from the sign of the input value.

A narrowing conversion of achar to an integral typeT likewise simply discards all but then lowest order bits, wheren is the number of bits used to represent typeT. In addition to a possible loss of information about the magnitude of the numeric value, this may cause the resulting value to be a negative number, even though chars represent 16-bit unsigned integer values.

A narrowing conversion of a floating-point number to an integral typeT takes two steps:

  1. In the first step, the floating-point number is converted either to along, ifT islong, or to anint, ifT isbyte,short,char, orint, as follows:

    • If the floating-point number is NaN (§4.2.3), the result of the first step of the conversion is anint orlong0.

    • Otherwise, if the floating-point number is not an infinity, the floating-point value is rounded to an integer valueV using the round toward zero rounding policy (§4.2.4). Then there are two cases:

      1. IfT islong, and this integer value can be represented as along, then the result of the first step is thelong valueV.

      2. Otherwise, if this integer value can be represented as anint, then the result of the first step is theint valueV.

    • Otherwise, one of the following two cases must be true:

      1. The value must be too small (a negative value of large magnitude or negative infinity), and the result of the first step is the smallest representable value of typeint orlong.

      2. The value must be too large (a positive value of large magnitude or positive infinity), and the result of the first step is the largest representable value of typeint orlong.

  2. In the second step:

    • IfT isint orlong, the result of the conversion is the result of the first step.

    • IfT isbyte,char, orshort, the result of the conversion is the result of a narrowing conversion to typeT (§5.1.3) of the result of the first step.

A narrowing conversion fromdouble tofloat occurs as determined by the rules of IEEE 754 for converting between binary floating-point formats, using the round to nearest rounding policy (§15.4). This conversion can lose precision, but also lose range, resulting in afloat zero from a nonzerodouble and afloat infinity from a finitedouble. Adouble NaN is converted to afloat NaN and adouble infinity is converted to the same-signedfloat infinity.

Despite the fact that overflow, underflow, or other loss of information may occur, a narrowing primitive conversion never results in a run-time exception (§11.1.1).

Example 5.1.3-1. Narrowing Primitive Conversion

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);    }}

This program produces the output:

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

The results forchar,int, andlong are unsurprising, producing the minimum and maximum representable values of the type.

The results forbyte andshort lose information about the sign and magnitude of the numeric values and also lose precision. The results can be understood by examining the low order bits of the minimum and maximumint. The minimumint is, in hexadecimal,0x80000000, and the maximum int is0x7fffffff. This explains theshort results, which are the low 16 bits of these values, namely,0x0000 and0xffff; it explains the char results, which also are the low 16 bits of these values, namely,'\u0000' and'\uffff'; and it explains the byte results, which are the low 8 bits of these values, namely,0x00 and0xff.


Example 5.1.3-2. Narrowing Primitive Conversions that lose information

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));        // An int value too big for 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);    }}

This program produces the output:

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

5.1.4. Widening and Narrowing Primitive Conversion

The following conversion combines both widening and narrowing primitive conversions:

  • byte tochar

First, thebyte is converted to anint via widening primitive conversion (§5.1.2), and then the resultingint is converted to achar by narrowing primitive conversion (§5.1.3).

5.1.5. Widening Reference Conversion

Awidening reference conversion exists from any reference typeS to any reference typeT, providedS is a subtype ofT (§4.10).

Widening reference conversions never require a special action at run time and therefore never throw an exception at run time. They consist simply in regarding a reference as having some other type in a manner that can be proved correct at compile time.

The null type is not a reference type (§4.1), and so a widening reference conversion does not exist from the null type to a reference type. However, many conversion contexts explicitly allow the null type to be converted to a reference type.

5.1.6. Narrowing Reference Conversion

Anarrowing reference conversion treats expressions of a reference typeS as expressions of a different reference typeT, whereS is not a subtype ofT. The supported pairs of types are defined in§5.1.6.1. Unlike widening reference conversion, the types need not be directly related. However, there are restrictions that prohibit conversion between certain pairs of types when it can be statically proven that no value can be of both types.

A narrowing reference conversion may require a test at run time to validate that a value of typeS is a legitimate value of typeT. However, due to the lack of parameterized type information at run time, some conversions cannot be fully validated by a run time test; they are flagged at compile time (§5.1.6.2). For conversions that can be fully validated by a run time test, and for certain conversions that involve parameterized type information but can still be partially validated at run time, aClassCastException is thrown if the test fails (§5.1.6.3).

5.1.6.1. Allowed Narrowing Reference Conversion

A narrowing reference conversion exists from reference typeS to reference typeT if all of the following are true:

  • S is not a subtype ofT (§4.10)

  • If there exists a parameterized typeX that is a supertype ofT, and a parameterized typeY that is a supertype ofS, such that the erasures ofX andY are the same, thenX andY are not provably distinct (§4.5).

    Using types from thejava.util package as an example, no narrowing reference conversion exists fromArrayList<String> toArrayList<Object>, or vice versa, because the type argumentsString andObject are provably distinct. For the same reason, no narrowing reference conversion exists fromArrayList<String> toList<Object>, or vice versa. The rejection of provably distinct types is a simple static gate to prevent "stupid" narrowing reference conversions.

  • One of the following cases applies:

    1. S is a class or interface type, andT is a class or interface type, andS names a class or interface that is not disjoint from the class or interface named byT. ("disjoint" is defined below.)

    2. S is the class typeObject or the interface typejava.io.Serializable orCloneable (the only interfaces implemented by arrays (§10.8)), andT is an array type.

    3. S is an array typeSC[], that is, an array of components of typeSC;T is an array typeTC[], that is, an array of components of typeTC; and a narrowing reference conversion exists fromSC toTC.

    4. S is a type variable, and a narrowing reference conversion exists from the upper bound ofS toT.

    5. T is a type variable, and either a widening reference conversion or a narrowing reference conversion exists fromS to the upper bound ofT.

    6. S is an intersection typeS1& ...&Sn, and for alli (1in), either a widening reference conversion or a narrowing reference conversion exists fromSi toT.

    7. T is an intersection typeT1& ...&Tn, and for alli (1in), either a widening reference conversion or a narrowing reference conversion exists fromS toTi.

A class or interface isdisjoint from another class or interface if it can be determined statically that they have no instances in common (other than thenull value). The rules for disjointess are as follows:

  • A class namedC is disjoint from an interface namedI if (i) it is not the case thatC<:I, and (ii) one of the following cases applies:

    • C isfinal.

    • C issealed, and all of the permitted direct subclasses ofC are disjoint fromI.

    • C is freely extensible (§8.1.1.2), andI issealed, andC is disjoint from all of the permitted direct subclasses and subinterfaces ofI.

  • An interface namedI is disjoint from a class namedC ifC is disjoint fromI.

  • A class namedC is disjoint from another class namedD if (i) it is not the case thatC<:D, and (ii) it is not the case thatD<:C.

  • An interface namedI is disjoint from another interface namedJ if (i) it is not that case thatI<:J, and (ii) it is not the case thatJ<:I, and (iii) one of the following cases applies:

    • I issealed, and all of the permitted direct subclasses and subinterfaces ofI are disjoint fromJ.

    • J issealed, andI is disjoint from all the permitted direct subclasses and subinterfaces ofJ.

Whether a class isfinal has the most bearing on whether the class is disjoint from interfaces. Consider the following declarations:

interface I   {}final class C {}

As classC isfinal and does not implementI, there can be no instances ofC that are also an instance ofI, soC andI are disjoint. Therefore, there is no narrowing reference conversion fromC toI.

In contrast, consider the following declarations:

interface J {}class D     {}

Even though classD does not implementJ, it is still possible for an instance ofD to be an instance ofJ, for example, if the following declaration occurs:

class E extends D implements J {}

For this reason,D is not disjoint fromJ, and there is a narrowing reference conversion fromD toJ.

The final clause above implies that two freely extensible interfaces (§9.1.1.4) are not disjoint.

5.1.6.2. Checked and Unchecked Narrowing Reference Conversions

A narrowing reference conversion is eitherchecked orunchecked. These terms refer to the ability of the Java Virtual Machine to validate, or not, the type correctness of the conversion.

If a narrowing reference conversion is unchecked, then the Java Virtual Machine will not be able to fully validate its type correctness, possibly leading to heap pollution (§4.12.2). To flag this to the programmer, an unchecked narrowing reference conversion causes a compile-timeunchecked warning, unless suppressed by@SuppressWarnings (§9.6.4.5). Conversely, if a narrowing reference conversion is not unchecked, then it is checked; the Java Virtual Machine will be able to fully validate its type correctness, so no warning is given at compile time.

The unchecked narrowing reference conversions are as follows:

  • A narrowing reference conversion from a typeS to a parameterized class or interface typeT is unchecked, unless at least one of the following is true:

    • All of the type arguments ofT are unbounded wildcards.

    • T<:S, andS has no subtypeX other thanT where the type arguments ofX are not contained in the type arguments ofT.

  • A narrowing reference conversion from a typeS to a type variableT is unchecked.

  • A narrowing reference conversion from a typeS to an intersection typeT1& ...&Tn is unchecked if there exists aTi (1in) such thatS is not a subtype ofTi and a narrowing reference conversion fromS toTi is unchecked.

5.1.6.3. Narrowing Reference Conversions at Run Time

Allchecked narrowing reference conversions require a validity check at run time. Primarily, these conversions are to class and interface types that are not parameterized.

Someunchecked narrowing reference conversions require a validity check at run time. This depends on whether the unchecked narrowing reference conversion iscompletely unchecked orpartially unchecked. A partially unchecked narrowing reference conversion requires a validity check at run time, while a completely unchecked narrowing reference conversion does not.

These terms refer to the compatibility of the types involved in the conversionwhen viewed as raw types. If the conversion is conceptually an "upcast", then the conversion iscompletely unchecked; no run time test is needed because the conversion is legal in the non-generic type system of the Java Virtual Machine. Conversely, if the conversion is conceptually a "downcast", then the conversion ispartially unchecked; even in the non-generic type system of the Java Virtual Machine, a run time check is needed to test the compatibility of the (raw) types involved in the conversion.

Using types from thejava.util package as an example, a conversion fromArrayList<String> toCollection<T> is completely unchecked, because the (raw) typeArrayList is a subtype of the (raw) typeCollection in the Java Virtual Machine. Conversely, a conversion fromCollection<T> toArrayList<String> is partially unchecked, because the (raw) typeCollection is not a subtype of the (raw) typeArrayList in the Java Virtual Machine.

The categorization of an unchecked narrowing reference conversion is as follows:

  • An unchecked narrowing reference conversion fromS to a non-intersection typeT is completely unchecked if |S|<: |T|.

    Otherwise, it is partially unchecked.

  • An unchecked narrowing reference conversion fromS to an intersection typeT1& ...&Tn is completely unchecked if, for alli (1in), eitherS<:Ti or a narrowing reference conversion fromS toTi is completely unchecked.

    Otherwise, it is partially unchecked.

The run time validity check for a checked or partially unchecked narrowing reference conversion is as follows:

  • If the value at run time isnull, then the conversion is allowed.

  • Otherwise, letR be the class of the object referred to by the value, and letT be the erasure (§4.6) of the type being converted to. Then:

    • IfR is an ordinary class (not an array class):

      • IfT is a class type, thenR must be either the same class asT (§4.3.4) or a subclass ofT, or aClassCastException is thrown.

      • IfT is an interface type, thenR must implement interfaceT (§8.1.5), or aClassCastException is thrown.

      • IfT is an array type, then aClassCastException is thrown.

    • IfR is an interface:

      Note thatR cannot be an interface when these rules are first applied for any given conversion, butR may be an interface if the rules are applied recursively because the run-time reference value may refer to an array whose element type is an interface type.

      • IfT is a class type, thenT must beObject (§4.3.2), or aClassCastException is thrown.

      • IfT is an interface type, thenR must be either the same interface asT or a subinterface ofT, or aClassCastException is thrown.

      • IfT is an array type, then aClassCastException is thrown.

    • IfR is a class representing an array typeRC[], that is, an array of components of typeRC:

      • IfT is a class type, thenT must beObject (§4.3.2), or aClassCastException is thrown.

      • IfT is an interface type, thenT must be the typejava.io.Serializable orCloneable (the only interfaces implemented by arrays), or aClassCastException is thrown.

      • IfT is an array typeTC[], that is, an array of components of typeTC, then aClassCastException is thrown unless eitherTC andRC are the same primitive type, orTC andRC are reference types and are allowed by a recursive application of these run-time rules.

If the conversion is to an intersection typeT1& ...&Tn, then for alli (1in), any run-time check required for a conversion fromS toTi is also required for the conversion to the intersection type.

5.1.7. Boxing Conversion

Boxing conversion treats expressions of a primitive type as expressions of a corresponding reference type. Specifically, the following nine conversions are called theboxing conversions:

  • From typeboolean to typeBoolean

  • From typebyte to typeByte

  • From typeshort to typeShort

  • From typechar to typeCharacter

  • From typeint to typeInteger

  • From typelong to typeLong

  • From typefloat to typeFloat

  • From typedouble to typeDouble

  • From the null type to the null type

    This rule is necessary because the conditional operator (§15.25) applies boxing conversion to the types of its operands, and uses the result in further calculations.

At run time, boxing conversion proceeds as follows:

  • Ifp is a value of typeboolean, then boxing conversion convertsp into a referencer of class and typeBoolean, such thatr.booleanValue() ==p

  • Ifp is a value of typebyte, then boxing conversion convertsp into a referencer of class and typeByte, such thatr.byteValue() ==p

  • Ifp is a value of typechar, then boxing conversion convertsp into a referencer of class and typeCharacter, such thatr.charValue() ==p

  • Ifp is a value of typeshort, then boxing conversion convertsp into a referencer of class and typeShort, such thatr.shortValue() ==p

  • Ifp is a value of typeint, then boxing conversion convertsp into a referencer of class and typeInteger, such thatr.intValue() ==p

  • Ifp is a value of typelong, then boxing conversion convertsp into a referencer of class and typeLong, such thatr.longValue() ==p

  • Ifp is a value of typefloat then:

    • Ifp is not NaN, then boxing conversion convertsp into a referencer of class and typeFloat, such thatr.floatValue() evaluates top

    • Otherwise, boxing conversion convertsp into a referencer of class and typeFloat such thatr.isNaN() evaluates totrue

  • Ifp is a value of typedouble, then:

    • Ifp is not NaN, boxing conversion convertsp into a referencer of class and typeDouble, such thatr.doubleValue() evaluates top

    • Otherwise, boxing conversion convertsp into a referencer of class and typeDouble such thatr.isNaN() evaluates totrue

  • Ifp is a value of any other type, boxing conversion is equivalent to an identity conversion (§5.1.1).

If the valuep being boxed is the result of evaluating a constant expression (§15.29) of typeboolean,byte,char,short,int, orlong, and the result istrue,false, a character in the range'\u0000' to'\u007f' inclusive, or an integer in the range-128 to127 inclusive, then leta andb be the results of any two boxing conversions ofp. It is always the case thata==b.

Ideally, boxing a primitive value would always yield an identical reference. In practice, this may not be feasible using existing implementation techniques. The rule above is a pragmatic compromise, requiring that certain common values always be boxed into indistinguishable objects. The implementation may cache these, lazily or eagerly. For other values, the rule disallows any assumptions about the identity of the boxed values on the programmer's part. This allows (but does not require) sharing of some or all of these references.

This ensures that in most common cases, the behavior will be the desired one, without imposing an undue performance penalty, especially on small devices. Less memory-limited implementations might, for example, cache allchar andshort values, as well asint andlong values in the range of -32K to +32K.

A boxing conversion may result in anOutOfMemoryError if a new instance of one of the wrapper classes (Boolean,Byte,Character,Short,Integer,Long,Float, orDouble) needs to be allocated and insufficient storage is available.

5.1.8. Unboxing Conversion

Unboxing conversion treats expressions of a reference type as expressions of a corresponding primitive type. Specifically, the following eight conversions are called theunboxing conversions:

  • From typeBoolean to typeboolean

  • From typeByte to typebyte

  • From typeShort to typeshort

  • From typeCharacter to typechar

  • From typeInteger to typeint

  • From typeLong to typelong

  • From typeFloat to typefloat

  • From typeDouble to typedouble

At run time, unboxing conversion proceeds as follows:

  • Ifr is a reference of typeBoolean, then unboxing conversion convertsr intor.booleanValue()

  • Ifr is a reference of typeByte, then unboxing conversion convertsr intor.byteValue()

  • Ifr is a reference of typeCharacter, then unboxing conversion convertsr intor.charValue()

  • Ifr is a reference of typeShort, then unboxing conversion convertsr intor.shortValue()

  • Ifr is a reference of typeInteger, then unboxing conversion convertsr intor.intValue()

  • Ifr is a reference of typeLong, then unboxing conversion convertsr intor.longValue()

  • Ifr is a reference of typeFloat, unboxing conversion convertsr intor.floatValue()

  • Ifr is a reference of typeDouble, then unboxing conversion convertsr intor.doubleValue()

  • Ifr isnull, unboxing conversion throws aNullPointerException

A type is said to beconvertible to a numeric type if it is a numeric type (§4.2), or it is a reference type that may be converted to a numeric type by unboxing conversion.

A type is said to beconvertible to an integral type if it is an integral type, or it is a reference type that may be converted to an integral type by unboxing conversion.

5.1.9. Unchecked Conversion

LetG name a generic type declaration withn type parameters.

There is anunchecked conversion from the raw class or interface type (§4.8)G to any parameterized type of the formG<T1,...,Tn>.

There is anunchecked conversion from the raw array typeG[]k to any array type of the formG<T1,...,Tn>[]k. (The notation[]k indicates an array type ofk dimensions.)

Use of an unchecked conversion causes a compile-timeunchecked warning unless all type argumentsTi (1in) are unbounded wildcards (§4.5.1), or the warning is suppressed by@SuppressWarnings (§9.6.4.5).

Unchecked conversion is used to enable a smooth interoperation of legacy code, written before the introduction of generic types, with libraries that have undergone a conversion to use genericity (a process we call generification). In such circumstances (most notably, clients of the Collections Framework injava.util), legacy code uses raw types (e.g.Collection instead ofCollection<String>). Expressions of raw types are passed as arguments to library methods that use parameterized versions of those same types as the types of their corresponding formal parameters.

Such calls cannot be shown to be statically safe under the type system using generics. Rejecting such calls would invalidate large bodies of existing code, and prevent them from using newer versions of the libraries. This in turn, would discourage library vendors from taking advantage of genericity. To prevent such an unwelcome turn of events, a raw type may be converted to an arbitrary invocation of the generic type declaration to which the raw type refers. While the conversion is unsound, it is tolerated as a concession to practicality. An unchecked warning is issued in such cases.

5.1.10. Capture Conversion

LetG name a generic type declaration (§8.1.2,§9.1.2) withn type parametersA1,...,An with corresponding boundsU1,...,Un.

There exists acapture conversion from a parameterized typeG<T1,...,Tn> (§4.5) to a parameterized typeG<S1,...,Sn>, where, for 1in :

  • IfTi is a wildcard type argument (§4.5.1) of the form?, thenSi is a fresh type variable whose upper bound isUi[A1:=S1,...,An:=Sn] and whose lower bound is the null type (§4.1).

  • IfTi is a wildcard type argument of the form?extendsBi, thenSi is a fresh type variable whose upper bound is glb(Bi,Ui[A1:=S1,...,An:=Sn]) and whose lower bound is the null type.

    glb(V1,...,Vm) is defined asV1& ...&Vm.

    It is a compile-time error if, for any two classes (not interfaces)Vi andVj,Vi is not a subclass ofVj or vice versa.

  • IfTi is a wildcard type argument of the form?superBi, thenSi is a fresh type variable whose upper bound isUi[A1:=S1,...,An:=Sn] and whose lower bound isBi.

  • Otherwise,Si =Ti.

Capture conversion on any type other than a parameterized type (§4.5) acts as an identity conversion (§5.1.1).

Capture conversion is not applied recursively.

Capture conversion never requires a special action at run time and therefore never throws an exception at run time.

Capture conversion is designed to make wildcards more useful. To understand the motivation, let's begin by looking at the methodjava.util.Collections.reverse():

public static void reverse(List<?> list);

The method reverses the list provided as a parameter. It works for any type of list, and so the use of the wildcard typeList<?> as the type of the formal parameter is entirely appropriate.

Now consider how one would implementreverse():

public static void reverse(List<?> list) { rev(list); }private static <T> void rev(List<T> list) {    List<T> tmp = new ArrayList<T>(list);    for (int i = 0; i < list.size(); i++) {        list.set(i, tmp.get(list.size() - i - 1));    }}

The implementation needs to copy the list, extract elements from the copy, and insert them into the original. To do this in a type-safe manner, we need to give a name,T, to the element type of the incoming list. We do this in the private service methodrev(). This requires us to pass the incoming argument list, of typeList<?>, as an argument torev(). In general,List<?> is a list of unknown type. It is not a subtype ofList<T>, for any typeT. Allowing such a subtype relation would be unsound. Given the method:

public static <T> void fill(List<T> l, T obj)

the following code would undermine the type system:

List<String> ls = new ArrayList<String>();List<?> l = ls;Collections.fill(l, new Object());  // not legal - but assume it was!String s = ls.get(0); // ClassCastException - ls contains                      // Objects, not Strings.

So, without some special dispensation, we can see that the call fromreverse() torev() would be disallowed. If this were the case, the author ofreverse() would be forced to write its signature as:

public static <T> void reverse(List<T> list)

This is undesirable, as it exposes implementation information to the caller. Worse, the designer of an API might reason that the signature using a wildcard is what the callers of the API require, and only later realize that a type safe implementation was precluded.

The call fromreverse() torev() is in fact harmless, but it cannot be justified on the basis of a general subtyping relation betweenList<?> andList<T>. The call is harmless, because the incoming argument is doubtless a list of some type (albeit an unknown one). If we can capture this unknown type in a type variableX, we can inferT to beX. That is the essence of capture conversion. The specification of course must cope with complications, like non-trivial (and possibly recursively defined) upper or lower bounds, the presence of multiple arguments etc.

Mathematically sophisticated readers will want to relate capture conversion to established type theory. Readers unfamiliar with type theory can skip this discussion - or else study a suitable text, such asTypes and Programming Languages by Benjamin Pierce, and then revisit this section.

Here then is a brief summary of the relationship of capture conversion to established type theoretical notions. Wildcard types are a restricted form of existential types. Capture conversion corresponds loosely to an opening of a value of existential type. A capture conversion of an expressione can be thought of as anopen ofe in a scope that comprises the top level expression that enclosese.

The classicalopen operation on existentials requires that the captured type variable must not escape the opened expression. Theopen that corresponds to capture conversion is always on a scope sufficiently large that the captured type variable can never be visible outside that scope. The advantage of this scheme is that there is no need for aclose operation, as defined in the paperOn Variance-Based Subtyping for Parametric Types by Atsushi Igarashi and Mirko Viroli, in the proceedings of the 16th European Conference on Object Oriented Programming (ECOOP 2002). For a formal account of wildcards, seeWild FJ by Mads Torgersen, Erik Ernst and Christian Plesner Hansen, in the 12th workshop on Foundations of Object Oriented Programming (FOOL 2005).

5.1.11. String Conversion

Any type may be converted to typeString bystring conversion.

A valuex of primitive typeT is first converted to a reference value as if by giving it as an argument to an appropriate class instance creation expression (§15.9):

  • IfT isboolean, then usenew Boolean(x).

  • IfT ischar, then usenew Character(x).

  • IfT isbyte,short, orint, then usenew Integer(x).

  • IfT islong, then usenew Long(x).

  • IfT isfloat, then usenew Float(x).

  • IfT isdouble, then usenew Double(x).

This reference value is then converted to typeString by string conversion.

Now only reference values need to be considered:

  • If the reference isnull, it is converted to the string "null" (four ASCII charactersn,u,l,l).

  • Otherwise, the conversion is performed as if by an invocation of thetoString method of the referenced object with no arguments; but if the result of invoking thetoString method isnull, then the string "null" is used instead.

    ThetoString method is defined by the primordial classObject (§4.3.2). Many classes override it, notablyBoolean,Character,Integer,Long,Float,Double, andString.

5.1.12. Forbidden Conversions

Any conversion that is not explicitly allowed is forbidden.

5.2. Assignment Contexts

Assignment contexts allow the value of an expression to be assigned (§15.26) to a variable; the type of the expression must be converted to the type of the variable.

Assignment contexts allow the use of one of the following:

  • an identity conversion (§5.1.1)

  • a widening primitive conversion (§5.1.2)

  • a widening reference conversion (§5.1.5)

  • a widening reference conversion followed by an unboxing conversion

  • a widening reference conversion followed by an unboxing conversion, then followed by a widening primitive conversion

  • a boxing conversion (§5.1.7)

  • a boxing conversion followed by a widening reference conversion

  • an unboxing conversion (§5.1.8)

  • an unboxing conversion followed by a widening primitive conversion

If, after the conversions listed above have been applied, the resulting type is a raw type (§4.8), an unchecked conversion (§5.1.9) may then be applied.

In addition, if the expression is a constant expression (§15.29) of typebyte,short,char, orint:

  • A narrowing primitive conversion may be used if the variable is of typebyte,short, orchar, and the value of the constant expression is representable in the type of the variable.

  • A narrowing primitive conversion followed by a boxing conversion may be used if the variable is of typeByte,Short, orCharacter, and the value of the constant expression is representable in the typebyte,short, orchar respectively.

The compile-time narrowing of constant expressions means that code such as:

byte theAnswer = 42;

is allowed. Without the narrowing, the fact that the integer literal42 has typeint would mean that a cast tobyte would be required:

byte theAnswer = (byte)42;  // cast is permitted but not required

Finally, a value of the null type (the null reference is the only such value) may be assigned to any reference type, resulting in a null reference of that type.

It is a compile-time error if the chain of conversions contains two parameterized types that are not in the subtype relation (§4.10).

An example of such an illegal chain would be:

Integer, Comparable<Integer>, Comparable, Comparable<String>

The first three elements of the chain are related by widening reference conversion, while the last entry is derived from its predecessor by unchecked conversion. However, this is not a valid assignment conversion, because the chain contains two parameterized types,Comparable<Integer> andComparable<String>, that are not subtypes.

If the type of an expression can be converted to the type of a variable by assignment conversion, we say the expression (or its value) isassignable to the variable or, equivalently, that the type of the expression isassignment compatible with the type of the variable.

The only exceptions that may arise from conversions in an assignment context are:

  • AClassCastException if, after the conversions above have been applied, the resulting value is an object which is not an instance of a subclass or subinterface of the erasure (§4.6) of the type of the variable.

    This circumstance can only arise as a result of heap pollution (§4.12.2). In practice, implementations need only perform casts when accessing a field or method of an object of parameterized type when the erased type of the field, or the erased return type of the method, differ from its unerased type.

  • AnOutOfMemoryError as a result of a boxing conversion.

  • ANullPointerException as a result of an unboxing conversion on a null reference.

  • AnArrayStoreException in special cases involving array elements or field access (§10.5,§15.26.1).

Example 5.2-1. Assignment for Primitive Types

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);    }}

This program produces the output:

f=12.0l=0x123d=1.2300000190734863

The following program, however, produces compile-time errors:

class Test {    public static void main(String[] args) {        short s = 123;        char c = s;    // error: would require cast        s = c;         // error: would require cast    }}

because not allshort values arechar values, and neither are allchar valuesshort values.


Example 5.2-2. Assignment for Reference Types

class Point { int x, y; }class Point3D extends Point { int z; }interface Colorable { void setColor(int color); }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    }}

The following test program illustrates assignment conversions on reference values, but fails to compile, as described in its comments. This example should be compared to the preceding one.

class Point { int x, y; }interface Colorable { void setColor(int color); }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    }}

Example 5.2-3. Assignment for Array Types

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    }}

In this example:

  • The value ofveclong cannot be assigned to aLong variable, becauseLong is a class type other thanObject. An array can be assigned only to a variable of a compatible array type, or to a variable of typeObject,Cloneable orjava.io.Serializable.

  • The value ofveclong cannot be assigned tovecshort, because they are arrays of primitive type, andshort andlong are not the same primitive type.

  • The value ofcpvec can be assigned topvec, because any reference that could be the value of an expression of typeColoredPoint can be the value of a variable of typePoint. The subsequent assignment of the newPoint to a component ofpvec then would throw anArrayStoreException (if the program were otherwise corrected so that it could be compiled), because aColoredPoint array cannot have an instance ofPoint as the value of a component.

  • The value ofpvec cannot be assigned tocpvec, because not every reference that could be the value of an expression of typePoint can correctly be the value of a variable of typeColoredPoint. If the value ofpvec at run time were a reference to an instance ofPoint[], and the assignment tocpvec were allowed, a simple reference to a component ofcpvec, say,cpvec[0], could return aPoint, and aPoint is not aColoredPoint. Thus to allow such an assignment would allow a violation of the type system. A cast may be used (§5.5,§15.16) to ensure thatpvec references aColoredPoint[]:

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

5.3. Invocation Contexts

Invocation contexts allow an argument value in a method or constructor invocation (§8.8.7.1,§15.9,§15.12) to be assigned to a corresponding formal parameter.

Strict invocation contexts allow the use of one of the following:

  • an identity conversion (§5.1.1)

  • a widening primitive conversion (§5.1.2)

  • a widening reference conversion (§5.1.5)

Loose invocation contexts allow a more permissive set of conversions, because they are only used for a particular invocation if no applicable declaration can be found using strict invocation contexts. Loose invocation contexts allow the use of one of the following:

  • an identity conversion (§5.1.1)

  • a widening primitive conversion (§5.1.2)

  • a widening reference conversion (§5.1.5)

  • a widening reference conversion followed by an unboxing conversion

  • a widening reference conversion followed by an unboxing conversion, then followed by a widening primitive conversion

  • a boxing conversion (§5.1.7)

  • a boxing conversion followed by widening reference conversion

  • an unboxing conversion (§5.1.8)

  • an unboxing conversion followed by a widening primitive conversion

If, after the conversions listed for an invocation context have been applied, the resulting type is a raw type (§4.8), an unchecked conversion (§5.1.9) may then be applied.

A value of the null type (the null reference is the only such value) may be assigned to any reference type.

It is a compile-time error if the chain of conversions contains two parameterized types that are not in the subtype relation (§4.10).

The only exceptions that may arise in an invocation context are:

  • AClassCastException if, after the type conversions above have been applied, the resulting value is an object which is not an instance of a subclass or subinterface of the erasure (§4.6) of the corresponding formal parameter type.

  • AnOutOfMemoryError as a result of a boxing conversion.

  • ANullPointerException as a result of an unboxing conversion on a null reference.

Neither strict nor loose invocation contexts include the implicit narrowing of integer constant expressions which is allowed in assignment contexts. The designers of the Java programming language felt that including these implicit narrowing conversions would add additional complexity to the rules of overload resolution (§15.12.2).

Thus, the program:

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    }}

causes a compile-time error because the integer literals12 and2 have typeint, so neither methodm matches under the rules of overload resolution. A language that included implicit narrowing of integer constant expressions would need additional rules to resolve cases like this example.

5.4. String Contexts

String contexts apply only to an operand of the binary+ operator which is not aString when the other operand is aString.

The target type in these contexts is alwaysString, and a string conversion (§5.1.11) of the non-String operand always occurs. Evaluation of the+ operator then proceeds as specified in§15.18.1.

5.5. Casting Contexts

Casting contexts allow the operand of a cast expression (§15.16) to be converted to the type explicitly named by the cast operator. Compared to assignment contexts and invocation contexts, casting contexts allow the use of more of the conversions defined in§5.1, and allow more combinations of those conversions.

If the expression is of a primitive type, then a casting context allows the use of one of the following:

  • an identity conversion (§5.1.1)

  • a widening primitive conversion (§5.1.2)

  • a narrowing primitive conversion (§5.1.3)

  • a widening and narrowing primitive conversion (§5.1.4)

  • a boxing conversion (§5.1.7)

  • a boxing conversion followed by a widening reference conversion (§5.1.5)

If the expression is of a reference type, then a casting context allows the use of one of the following:

  • an identity conversion (§5.1.1)

  • a widening reference conversion (§5.1.5)

  • a widening reference conversion followed by an unboxing conversion

  • a widening reference conversion followed by an unboxing conversion, then followed by a widening primitive conversion

  • a narrowing reference conversion (§5.1.6)

  • a narrowing reference conversion followed by an unboxing conversion

  • an unboxing conversion (§5.1.8)

  • an unboxing conversion followed by a widening primitive conversion

If the expression has the null type, then the expression may be cast to any reference type.

If a casting context makes use of a narrowing reference conversion that is checked or partially unchecked (§5.1.6.2,§5.1.6.3), then a run time check will be performed on the class of the expression's value, possibly causing aClassCastException. Otherwise, no run time check is performed.

If an expression can be converted to a reference type by a casting conversionother than a narrowing reference conversion that is unchecked, we say the expression (or its value) ischecked cast compatible with the reference type.

If an expression of reference typeS is checked cast compatible with another reference typeT, we say that the typeS ischecked cast convertible to typeT.

The following tables enumerate which conversions are used in certain casting contexts. Each conversion is signified by a symbol:

  • - signifies no conversion allowed

  • signifies identity conversion (§5.1.1)

  • ω signifies widening primitive conversion (§5.1.2)

  • η signifies narrowing primitive conversion (§5.1.3)

  • ωη signifies widening and narrowing primitive conversion (§5.1.4)

  • signifies widening reference conversion (§5.1.5)

  • signifies narrowing reference conversion (§5.1.6)

  • signifies boxing conversion (§5.1.7)

  • signifies unboxing conversion (§5.1.8)

In the tables, a comma between symbols indicates that a casting context uses one conversion followed by another. The typeObject means any reference type other than the eight wrapper classesBoolean,Byte,Short,Character,Integer,Long,Float,Double.

Table 5.5-A. Casting to primitive types

Tobyteshortcharintlongfloatdoubleboolean
From        
byteωωηωωωω-
shortηηωωωω-
charηηωωωω-
intηηηωωω-
longηηηηωω-
floatηηηηηω-
doubleηηηηηη-
boolean-------
Byte,ω-,ω,ω,ω,ω-
Short--,ω,ω,ω,ω-
Character--,ω,ω,ω,ω-
Integer---,ω,ω,ω-
Long----,ω,ω-
Float-----,ω-
Double-------
Boolean-------
Object,,,,,,,,

Table 5.5-B. Casting to reference types

ToByteShortCharacterIntegerLongFloatDoubleBooleanObject
From         
byte-------,
short-------,
char-------,
int-------,
long-------,
float-------,
double-------,
boolean-------,
Byte-------
Short-------
Character-------
Integer-------
Long-------
Float-------
Double-------
Boolean-------
Object

Example 5.5-1. Casting for Reference Types

class Point { int x, y; }interface Colorable { void setColor(int color); }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    }}

Here, the first compile-time error occurs because the class typesLong andPoint are unrelated (that is, they are not the same, and neither is a subclass of the other), so a cast between them will always fail.

The second compile-time error occurs because a variable of typeEndPoint can never reference a value that implements the interfaceColorable. This is becauseEndPoint is afinal type, and a variable of afinal type always holds a value of the same run-time type as its compile-time type. Therefore, the run-time type of variablee must be exactly the typeEndPoint, and typeEndPoint does not implementColorable.


Example 5.5-2. Casting for Array Types

class Point {    int x, y;    Point(int x, int y) { this.x = x; this.y = y; }    public String toString() { return "("+x+","+y+")"; }}interface Colorable { void setColor(int color); }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(" }");    }}

This program compiles without errors and produces the output:

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

Example 5.5-3. Casting Incompatible Types at Run Time

class Point { int x, y; }interface Colorable { void setColor(int color); }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);    }}

This program uses casts to compile, but it throws exceptions at run time, because the types are incompatible.


5.6. Numeric Contexts

Numeric contexts apply to the operands of arithmetic operators, array creation and access expressions, conditional expressions, and the result expressions ofswitch expressions.

An expression appears in anumeric arithmetic context if the expression is one of the following:

  • The operand of a unary plus operator+, unary minus operator-, or bitwise complement operator~ (§15.15.3,§15.15.4,§15.15.5)

  • An operand of a multiplicative operator*,/, or% (§15.17)

  • An operand of an addition or subtraction operator for numeric types+ or- (§15.18.2)

  • An operand of a shift operator<<,>>, or>>> (§15.19). Operands of these shift operators are treated separately rather than as a group. Along shift distance (right operand) does not promote the value being shifted (left operand) tolong.

  • An operand of a numerical comparison operator<,<=,>, or>= (§15.20.1)

  • An operand of a numerical equality operator== or!= (§15.21.1)

  • An operand of an integer bitwise operator&,^, or| (§15.22.1)

An expression appears in anumeric array context if the expression is one of the following:

  • A dimension expression in an array creation expression (§15.10.1)

  • The index expression in an array access expression (§15.10.3)

An expression appears in anumeric choice context if the expression is one of the following:

  • The second or third operand of a numeric conditional expression (§15.25.2)

  • A result expression of a standaloneswitch expression (§15.28.1) where all the result expressions are convertible to a numeric type

Numeric promotion determines thepromoted type of all the expressions in a numeric context. The promoted type is chosen such that each expression can be converted to the promoted type, and, in the case of an arithmetic operation, the operation is defined for values of the promoted type. The order of expressions in a numeric context is not significant for numeric promotion. The rules are as follows:

  1. If any expression is of a reference type, it is subjected to unboxing conversion (§5.1.8).

  2. Next, widening primitive conversion (§5.1.2) and narrowing primitive conversion (§5.1.3) are applied to some expressions, according to the following rules:

    • If any expression is of typedouble, then the promoted type isdouble, and other expressions that are not of typedouble undergo widening primitive conversion todouble.

    • Otherwise, if any expression is of typefloat, then the promoted type isfloat, and other expressions that are not of typefloat undergo widening primitive conversion tofloat.

    • Otherwise, if any expression is of typelong, then the promoted type islong, and other expressions that are not of typelong undergo widening primitive conversion tolong.

    • Otherwise, none of the expressions are of typedouble,float, orlong. In this case, the kind of context determines how the promoted type is chosen.

      In a numeric arithmetic context or a numeric array context, the promoted type isint, and any expressions that are not of typeint undergo widening primitive conversion toint.

      In a numeric choice context, the following rules apply:

      • If any expression is of typeint and is not a constant expression (§15.29), then the promoted type isint, and other expressions that are not of typeint undergo widening primitive conversion toint.

      • Otherwise, if any expression is of typeshort, and every other expression is either of typeshort or of typebyte or a constant expression of typeint with a value that is representable in the typeshort, then the promoted type isshort, and thebyte expressions undergo widening primitive conversion toshort, and theint expressions undergo narrowing primitive conversion toshort.

      • Otherwise, if any expression is of typebyte, and every other expression is either of typebyte or a constant expression of typeint with a value that is representable in the typebyte, then the promoted type isbyte, and theint expressions undergo narrowing primitive conversion tobyte.

      • Otherwise, if any expression is of typechar, and every other expression is either of typechar or a constant expression of typeint with a value that is representable in the typechar, then the promoted type ischar, and theint expressions undergo narrowing primitive conversion tochar.

      • Otherwise, the promoted type isint, and all the expressions that are not of typeint undergo widening primitive conversion toint.

Unary numeric promotion consists of applying numeric promotion to a single expression that occurs in a numeric arithmetic context or a numeric array context.

Binary numeric promotion consists of applying numeric promotion to a pair of expressions that occur in a numeric arithmetic context.

General numeric promotion consists of applying numeric promotion to all the expressions that occur in a numeric choice context.

Example 5.6-1. Unary Numeric Promotion

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));    }}

This program produces the output:

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

Example 5.6-2. Binary Numeric Promotion

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);    }}

This program produces the output:

70.25

The example converts the ASCII characterG to the ASCII control-G (BEL), by masking off all but the low 5 bits of the character. The7 is the numeric value of this control character.


5.7. Testing Contexts

Testing contexts allow the operand of a pattern match operator (§15.20.2), or the selector expression of aswitch expression or statement that has at least one patterncase label associated with its switch block (§14.11.1) to be converted to a type as part of the process of pattern matching. As pattern matching is an inherently conditional process (§14.30.2), it is expected that a testing context will make use of conversions that may fail at run time.

Testing contexts use similar conversions for reference types as casting contexts except that they do not permit narrowing reference conversions that are unchecked (§5.1.6.2).

If the expression is of a primitive type, then a testing context allows the use of an identity conversion (§5.1.1).

If the expression is of a reference type, then a testing context allows the use of one of the following:

  • an identity conversion (§5.1.1)

  • a widening reference conversion (§5.1.5)

  • a narrowing reference conversion that is checked (§5.1.6.2)

If the expression has the null type, then the expression may be converted to any reference type.

If a testing context makes use of a narrowing reference conversion, then a run time check will be performed on the class of the expression's value, possibly causing aClassCastException. Otherwise, no run time check is performed.


Prev   Next
Chapter 4. Types, Values, and Variables Home Chapter 6. Names

Legal Notice

[8]ページ先頭

©2009-2025 Movatter.jp