两个奇怪的现象
case1:打印Object对象时,无需强转:
Object val = 25;
System.out.println(val); // 直接打印,输出:25
// 不需要:(String)val 或 (Integer)val
case2:当我们要使用Object 数组中的元素时,需要强转:
class Node{int val;Node next;Node(int val){this.val = val;}
}
Object[] pair = new Object[]{23, new Node(5)};
int sum = (Integer) pair[0] + 10; // 必须强转
Node node = (Node) pair[1]; // 必须强转
// 不能直接:Node node = pair[1];
对于 case2,当我们不强转的话,编辑器会提示如下错误:
int sum = pair[0] + 10; // 报错:运算符 '+' 不能应用于 'java. lang. Object'、'int'
Node node = pair[1]; // 报错:需要的类型:Node 提供的类型:Object
背后的原因
case1不需要强转是因为在调用print
语句时,底层实际上已经做了以下操作:
System.out.println(val);↓
public void println(Object obj) {print(String.valueOf(obj));
}↓
public static String valueOf(Object obj) {return (obj == null) ? "null" : obj.toString();
}
可以看到,在调用 print
语句时,会把 Object 类型转换为 String 类型,然后调用这个对象的 toString()方法,(这也就是为什么我们通常需要重写 toString()
的原因)
打印方法内部已经帮我们做了类型转换,所以不再需要我们手动强转
那么 case2 为什么不使用强转会报错呢?
由于 java 有编译时类型、运行时类型,前者表示变量在代码中声明时的类型,后者表示变量在程序运行时实际指向的类型。
而编译器只能够看到编译时类型,并且由于编译器需要确保类型安全,所以就要阻止类型不匹配的运算
那么 case2 为什么使用了强转就不会报错呢
这是因为,当我们使用强转,就等于告诉编译器,这些变量在运行时是某某类型,由开发者来保证在运行时的类型和强转的类型一致,因此编译器就会根据用户强转后的类型来进行类型检查。