类型转换

编辑

类型转换将原始类型的值转换为目标类型的等效值。隐式类型转换推断目标类型,并在某些操作期间自动发生。显式类型转换指定目标类型,并强制作为其自身的操作发生。使用类型转换运算符 '()'来指定显式类型转换。

有关所有允许的类型转换的快速参考,请参阅类型转换表

错误

  • 如果在类型转换期间,目标类型不存在等效的值。
  • 如果给出了隐式类型转换,但需要显式类型转换。

语法

cast: '(' TYPE ')' expression

示例

  • 有效的类型转换。

    int i = (int)5L;         
    Map m = new HashMap();   
    HashMap hm = (HashMap)m; 

    声明 int i;将 long 5 显式转换为 int 5int 5;将 int 5 存储到 i

    声明 Map m;分配 HashMap 实例 → HashMap 引用;将 HashMap 引用 隐式转换为 Map 引用Map 引用;将 Map 引用 存储到 m

    声明 HashMap hm;从 m 加载 → Map 引用;将 Map 引用 显式转换为 HashMap 引用HashMap 引用;将 HashMap 引用 存储到 hm

数值类型转换

编辑

数值类型转换将原始数值类型的值转换为目标数值类型的等效值。当原始数值类型的值大于目标数值类型可以容纳的值时,两个数值类型值之间的转换会导致数据丢失。整数类型值和浮点类型值之间的转换可能会导致精度损失。

下表中以行的形式显示了每种数值类型的值所允许的转换

byte

short

char

int

long

float

double

byte

隐式

隐式

隐式

隐式

隐式

隐式

short

显式

显式

隐式

隐式

隐式

隐式

char

显式

显式

隐式

隐式

隐式

隐式

int

显式

显式

显式

隐式

隐式

隐式

long

显式

显式

显式

显式

隐式

隐式

float

显式

显式

显式

显式

显式

隐式

double

显式

显式

显式

显式

显式

显式

示例

  • 有效的数值类型转换。

    int a = 1;            
    long b = a;           
    short c = (short)b;   
    double e = (double)a; 

    声明 int a;将 int 1 存储到 a

    声明 long b;从 a 加载 → int 1;将 int 1 隐式转换为 long 1long 1;将 long 1 存储到 b

    声明 short c;从 b 加载 → long 1;将 long 1 显式转换为 short 1short 1;将 short 1 值存储到 c

    声明 double e;从 a 加载 → int 1;将 int 1 显式转换为 double 1.0;将 double 1.0 存储到 e;(请注意,由于隐式转换有效,因此显式转换是多余的)

  • 导致错误的无效数值类型转换。

    int a = 1.0; // error 
    int b = 2;            
    byte c = b;  // error 

    声明 int i错误 → 无法将 double 1.0 隐式转换为 int 1;(请注意,显式转换有效)

    声明 int b;将 int 2 存储到 b

    声明 byte c;从 b 加载 → int 2错误 → 无法将 int 2 隐式转换为 byte 2;(请注意,显式转换有效)

引用类型转换

编辑

引用类型转换将原始引用类型的值转换为目标引用类型的等效值。当原始引用类型是目标类型的后代时,允许两个引用类型值之间的隐式转换。当原始类型是目标类型的后代,或者目标类型是原始类型的后代时,允许两个引用类型值之间的显式转换。

示例

  • 有效的引用类型转换。

    List x;                        
    ArrayList y = new ArrayList(); 
    x = y;                         
    y = (ArrayList)x;              
    x = (List)y;                   

    声明 List x;将默认值 null 存储到 x

    声明 ArrayList y;分配 ArrayList 实例 → ArrayList 引用;将 ArrayList 引用 存储到 y

    y 加载 → ArrayList 引用;将 ArrayList 引用 隐式转换为 List 引用List 引用;将 List 引用 存储到 x;(请注意,ArrayListList 的后代)

    x 加载 → List 引用;将 List 引用 显式转换为 ArrayList 引用ArrayList 引用;将 ArrayList 引用 存储到 y

    y 加载 → ArrayList 引用;将 ArrayList 引用 显式转换为 List 引用List 引用;将 List 引用 存储到 x;(请注意,显式转换是多余的,隐式转换是有效的)

  • 导致错误的无效引用类型转换。

    List x = new ArrayList();          
    ArrayList y = x;          // error 
    Map m = (Map)x;           // error 

    声明 List x;分配 ArrayList 实例 → ArrayList 引用;将 ArrayList 引用 隐式转换为 List 引用List 引用;将 List 引用 存储到 x

    声明 ArrayList y;从 x 加载 → List 引用错误 → 无法将 List 引用 隐式转换为 ArrayList 引用;(请注意,由于 ArrayListList 的后代,因此显式转换有效)

    声明 ArrayList y;从 x 加载 → List 引用错误 → 无法将 List 引用 显式转换为 Map 引用;(请注意,由于 ListMap 都不是对方的后代,因此任何转换都无效)

动态类型转换

编辑

动态 ( def) 类型转换将原始 def 类型的值转换为任何目标类型的等效值,或者将任何原始类型的值转换为目标 def 类型的等效值。

始终允许从任何原始类型值到 def 类型值的隐式转换。始终允许从任何原始类型值到 def 类型值的显式转换,但永远没有必要。

当且仅当基于 def 类型值表示的当前类型值通常允许转换时,才允许从原始 def 类型值到任何目标类型值的隐式或显式转换。

示例

  • 使用任何原始类型到目标 def 类型的有效动态类型转换。

    def d0 = 3;               
    d0 = new ArrayList();     
    Object o = new HashMap(); 
    def d1 = o;               
    int i = d1.size();        

    声明 def d0;将 int 3 隐式转换为 def;将 int 3 存储到 d0

    分配 ArrayList 实例 → ArrayList 引用;将 ArrayList 引用 隐式转换为 defdef;将 def 存储到 d0

    声明 Object o;分配 HashMap 实例 → HashMap 引用;将 HashMap 引用 隐式转换为 Object 引用Object 引用;将 Object 引用 存储到 o

    声明 def d1;从 o 加载 → Object 引用;将 Object 引用 隐式转换为 defdef;将 def 存储到 d1

    声明 int i;从 d1 加载 → def;将 def 隐式转换为 HashMap 引用 → HashMap 引用`; 对 HashMap 引用 调用 sizeint 0;将 int 0 存储到 i;(请注意,由于 HashMapdef 类型值表示的最底层的后代类型值,因此 def 被隐式转换为 HashMap 引用

  • 使用原始 def 类型到任何目标类型的有效动态类型转换。

    def d = 1.0;         
    int i = (int)d;      
    d = 1;               
    float f = d;         
    d = new ArrayList(); 
    List l = d;          

    声明 def d;将 double 1.0 隐式转换为 defdef;将 def 存储到 d

    声明 int i;从 d 加载 → def;将 def 隐式转换为 double 1.0double 1.0;将 double 1.0 显式转换为 int 1int 1;将 int 1 存储到 i;(请注意,显式转换是必要的,因为 double 类型值不会隐式转换为 int 类型值)

    int 1 存储到 d;(请注意,d 代表的类型从 double 切换到 int

    声明 float i;从 d 加载 → def;将 def 隐式转换为 int 1int 1;将 int 1 隐式转换为 float 1.0float 1.0;将 float 1.0 存储到 f

    分配 ArrayList 实例 → ArrayList 引用;将 ArrayList 引用 存储到 d;(请注意,d 代表的类型从 int 切换到 ArrayList

    声明 List l;从 d 加载 → def;将 def 隐式转换为 ArrayList 引用ArrayList 引用;将 ArrayList 引用 隐式转换为 List 引用List 引用;将 List 引用 存储到 l

  • 导致错误的无效动态类型转换。

    def d = 1;                  
    short s = d;       // error 
    d = new HashMap();          
    List l = d;        // error 

    声明 def d; 隐式转换 int 1defdef; 将 def 存储到 d

    声明 short s; 从 d 加载 → def; 隐式转换 defint 1int 1; 错误 → 无法隐式转换 int 1short 1; (注意显式转换是有效的)

    分配 HashMap 实例 → HashMap 引用; 隐式转换 HashMap 引用defdef; 将 def 存储到 d

    声明 List l; 从 d 加载 → def; 隐式转换 defHashMap 引用; 错误 → 无法隐式转换 HashMap 引用List 引用; (注意,由于 HashMapList 都不是对方的后代,因此没有转换是有效的)

字符串到字符的转换

编辑

使用转换运算符将 String 类型的值转换为 char 类型的值。

错误

  • 如果 String 类型的值的长度不是一个字符。
  • 如果 String 类型的值是 null

示例

  • 将字符串字面量转换为 char 类型的值。

    char c = (char)"C"; 
    c = (char)'c';      

    声明 char c; 显式转换 String "C"char Cchar C; 将 char C 存储到 c

    显式转换 String 'c'char cchar c; 将 char c 存储到 c

  • String 引用转换为 char 类型的值。

    String s = "s";   
    char c = (char)s; 

    声明 String s; 将 String "s" 存储到 s;

    声明 char cs 加载 → String "s"; 显式转换 String "s"char schar s; 将 char s 存储到 c

字符到字符串的转换

编辑

使用转换运算符将 char 类型的值转换为 String 类型的值。

示例

  • String 引用转换为 char 类型的值。

    char c = 65;          
    String s = (String)c; 

    声明 char c; 将 char 65 存储到 c;

    声明 String sc 加载 → char A; 显式转换 char AString "A"String "A"; 将 String "A" 存储到 s

装箱和拆箱

编辑

装箱是一种特殊的转换类型,用于将原始类型转换为其对应的引用类型。拆箱是相反的操作,用于将引用类型转换为其对应的原始类型。

在以下操作期间会发生隐式装箱/拆箱

  • def 类型和原始类型之间的转换会根据需要隐式装箱/拆箱,尽管在整个文档中这被称为隐式转换。
  • 方法/函数调用参数会根据需要隐式装箱/拆箱。
  • 当在原始类型值上调用引用类型方法时,原始类型值会被隐式装箱。

不允许显式装箱/拆箱。使用引用类型 API 显式地将原始类型值转换为其各自的引用类型值,反之亦然。

错误

  • 如果进行了显式转换以装箱/拆箱原始类型。

示例

  • 隐式装箱/拆箱的使用。

    List l = new ArrayList();       
    l.add(1);                       
    Integer I = Integer.valueOf(0); 
    int i = l.get(i);               

    声明 List l; 分配 ArrayList 实例 → ArrayList 引用; 将 ArrayList 引用 存储到 l;

    l 加载 → List 引用; 隐式转换 int 1defdef; 使用参数 (def) 调用 List 引用 上的 add; (注意,在内部,int 1 被装箱为 Integer 1 以存储为 def 类型的值)

    声明 Integer I; 使用 (int 0) 的参数调用 Integer 上的 valueOfInteger 0; 将 Integer 0 存储到 I;

    声明 int i; 从 I 加载 → Integer 0; 拆箱 Integer 0int 0; 从 l 加载 → List 引用; 使用参数 (int 0) 调用 List 引用 上的 getdef; 隐式转换 defint 1int 1; 将 int 1 存储到 i; (注意,在从 def 类型的值加载时,内部将 int 1Integer 1 中拆箱)

  • 导致错误的无效装箱/拆箱的使用。

    Integer x = 1;                   // error 
    Integer y = (Integer)1;          // error 
    int a = Integer.valueOf(1);      // error 
    int b = (int)Integer.valueOf(1); // error 

    声明 Integer x; 错误 → 在赋值期间无法隐式装箱 int 1Integer 1

    声明 Integer y; 错误 → 在赋值期间无法显式装箱 int 1Integer 1

    声明 int a; 使用 (int 1) 的参数调用 Integer 上的 valueOfInteger 1; 错误 → 在赋值期间无法隐式拆箱 Integer 1int 1

    声明 int a; 使用 (int 1) 的参数调用 Integer 上的 valueOfInteger 1; 错误 → 在赋值期间无法显式拆箱 Integer 1int 1

提升

编辑

提升是指当单个值隐式转换为特定类型,或者多个值隐式转换为相同类型时,某些操作需要进行计算。每个需要提升的操作都有一个提升表,该表显示了基于值类型的所有必需的隐式转换。在编译时提升为 def 类型的值在运行时会根据 def 值表示的类型再次提升。

错误

  • 如果特定操作无法为给定值的类型找到允许的提升类型。

示例

  • 提升的使用。

    double d = 2 + 2.0; 
    def x = 1;          
    float f = x + 2.0F; 

    声明 double d; 提升 int 2double 2.0 @0:结果 double; 隐式转换 int 2double 2.0 @1double 2.0 @1; 将 double 2.0 @1double 2.0 @0 相加 → double 4.0; 将 double 4.0 存储到 d

    声明 def x; 隐式转换 int 1defdef; 将 def 存储到 x;

    声明 float f; 从 x 加载 → def; 隐式转换 defint 1int 1; 提升 int 1float 2.0:结果 float; 隐式转换 int 1float 1.0float `1.0; 将 float 1.0float 2.0 相加 → float 3.0; 将 float 3.0 存储到 f; (注意,此示例说明了在运行时进行的提升,因为在编译时进行的提升会解析为 def 类型的值)

允许的转换

编辑

下表显示了所有允许的转换。逐行读取这些表,其中原始类型显示在第一列,随后的每一列指示转换为指定目标类型的转换是隐式 (I)、显式 (E)、仅用于方法的装箱/拆箱 (A)、引用类型转换 (@) 还是不允许 (-)。有关允许的引用类型转换,请参阅引用类型转换

原始/引用类型

O

N

T

b

y

s

c

i

j

f

d

B

Y

S

C

I

J

F

D

R

def

对象 ( O )

@

@

-

-

-

-

-

-

-

-

@

@

@

@

@

@

@

@

@

I

数字 ( N )

I

-

-

-

-

-

-

-

-

-

-

@

@

-

@

@

@

@

@

I

字符串 ( T )

I

-

-

-

-

-

-

-

-

-

-

-

-

E

-

-

-

-

-

I

布尔值 ( b )

A

-

-

-

-

-

-

-

-

-

A

-

-

-

-

-

-

-

-

I

字节 ( y )

A

A

-

-

I

E

I

I

I

I

-

A

A

-

A

A

A

A

-

I

短整型 ( s )

A

A

-

-

E

E

I

I

I

I

-

-

A

-

A

A

A

A

-

I

字符 ( c )

A

-

E

-

E

E

I

I

I

I

-

-

-

A

A

A

A

A

-

I

整型 ( i )

A

A

-

-

E

E

E

I

I

I

-

-

-

-

A

A

A

A

-

I

长整型 ( j )

A

A

-

-

E

E

E

E

I

I

-

-

-

-

-

A

A

A

-

I

单精度浮点型 ( f )

A

A

-

-

E

E

E

E

E

I

-

-

-

-

-

-

A

A

-

I

双精度浮点型 ( d )

A

A

-

-

E

E

E

E

E

E

-

-

-

-

-

-

-

A

-

I

布尔值 ( B )

A

-

-

A

-

-

-

-

-

-

-

-

-

-

-

-

-

-

@

I

字节 ( Y )

A

I

-

-

A

A

-

A

A

A

A

-

A

-

A

A

A

A

@

I

短整型 ( S )

A

I

-

-

-

A

-

A

A

A

A

-

-

-

A

A

A

A

@

I

字符 ( C )

A

-

-

-

-

-

A

A

A

A

A

-

-

-

A

A

A

A

@

I

整型 ( I )

A

-

-

-

-

-

-

A

A

A

A

-

-

-

-

A

A

A

@

I

长整型 ( J )

A

-

-

-

-

-

-

-

A

A

A

-

-

-

-

-

A

A

@

I

单精度浮点型 ( F )

A

-

-

-

-

-

-

-

-

A

A

-

-

-

-

-

-

A

@

I

双精度浮点型 ( D )

A

-

-

-

-

-

-

-

-

-

A

-

-

-

-

-

-

-

@

I

引用 ( R )

I

@

@

-

-

-

-

-

-

-

-

@

@

@

@

@

@

@

@

@

I

def 类型

O

N

T

b

y

s

c

i

j

f

d

B

Y

S

C

I

J

F

D

R

def 作为字符串

I

-

I

-

-

-

E

-

-

-

-

-

-

-

E

-

-

-

-

@

def 作为布尔值/布尔值

I

-

-

I

-

-

-

-

-

-

-

I

-

-

-

-

-

-

-

@

def 作为字节/字节

I

-

-

-

I

I

E

I

I

I

I

-

I

I

E

I

I

I

I

@

def 作为短整型/短整型

I

-

-

-

E

I

E

I

I

I

I

-

E

I

E

I

I

I

I

@

def 作为字符/字符

I

-

-

-

E

E

I

I

I

I

I

-

E

E

I

I

I

I

I

@

def 作为整型/整型

I

-

-

-

E

E

E

I

I

I

I

-

E

E

E

I

I

I

I

@

def 作为长整型/长整型

I

-

-

-

E

E

E

E

I

I

I

-

E

E

E

E

I

I

I

@

def 作为单精度浮点型/单精度浮点型

I

-

-

-

E

E

E

E

E

I

I

-

E

E

E

E

E

I

I

@

def 作为双精度浮点型/双精度浮点型

I

-

-

-

E

E

E

E

E

E

I

-

E

E

E

E

E

E

I

@

def 作为引用

@

@

@

-

-

-

-

-

-

-

-

@

@

@

@

@

@

@

@

@