Java 中是否可能存在运行时类型不匹配?
Is it possible to have Runtime type mismatch in Java?
我正在阅读 OCaml 和 wiki,它说:
*its static type system renders runtime type mismatches impossible*
我明白为什么,但后来我想,为什么这在 OCaml(和 FP)中如此特别?您如何导致 Java 中的运行时类型不匹配?例如
boolean a = true;
int b = a + 1;
会return编译时出错。
编辑 1:
Haskell
func :: Int -> Bool
func i = if i > 0 then True else False
Java
boolean func (int i) {
if (i > 0) return true; else return false;
}
是不是在调用func
时两者都保证参数类型?
在 Java 中,您可以像这样导致运行时类型不匹配:
Object i = Integer.valueOf(6);
String s = (String) i;
System.out.println(s);
这将编译,因为 i
(Object
) 的编译时类型允许转换为 String
,但是在运行时,[= 的实际值11=](6
,因为 Integer
)将与 String
不兼容。
鉴于此,ClassCastException
被抛出。
考虑以下使用数组的代码:
// create an array of strings
String[] strings = new String[10];
// cast it to an array of objects
Object[] objects = strings;
// insert an object into the array
objects[0] = new Object(); // Run-time error occurs here
Java 允许编译,尽管将字符串数组转换为对象数组会引入 运行 时间错误的可能性。第 8 行演示了这一点,导致了 运行 次异常,该异常是专门为这种情况创建的类型:java.lang.ArrayStoreException: java.lang.Object
。
在 Java 中,类型可能不匹配。例如,以下抛出 ClassCastException
.
Object o = 1;
String s = (String) o;
但是,传递给方法的参数由编译器检查。
无法调用带有签名的方法
boolean func (int i)
除非i
是一个int
,并且不可能调用带有签名的方法
boolean func2 (String s)
除非 s
是 String
或 null
。
因此,您永远不会在运行时在 func2
的主体内获得 ClassCastException
,因为 s
不是 String
。
该 wiki 正在大体上讨论静态类型系统,并将它们与动态类型语言而不是其他静态类型语言进行对比。 OCaml 或 Haskell 没有关于不适用于所有静态类型语言的运行时类型不匹配的特定内容。
请注意,不可能有点虚伪。几乎所有静态类型语言都让您能够以有限的方式进行运行时类型化,因为如果没有它,某些任务将非常困难。事实上,您引用的那一段就列出了其中的几个案例,例如序列化。这里的其他答案在 Java 中提供了一些很好的例子。但是,绝大多数代码应该能够轻松避免运行时类型不匹配。
在Java中,不可能在可具体化类型(原始类型、非泛型引用类型、原始类型、所有参数化类型)之间存在类型不匹配通配符,或元素类型可具体化的数组类型)。
如果你有一个可具体化类型的变量,那么它在任何时间点持有的值都保证是该类型的值。对于引用类型,这意味着引用要么为空,要么指向一个对象,其运行时 class 是变量类型的子类型。这是有保证的,因为 Java 在存储类型不是变量类型的子类型的值时需要强制转换,并且向可具体化类型的强制转换是 checked 强制转换,这意味着它们是在运行时检查,如果类型不兼容,它将抛出异常而不是让类型不匹配。
另一方面,对于不可具体化的类型(例如参数化类型),可能存在类型不匹配(在[中称为"heap pollution" =26=] 术语)。这是因为对不可具体化类型的强制转换是 未经检查的强制转换.
List<String> foo = new ArrayList<String>();
foo.add("hi");
List<?> bar = foo;
List<Integer> baz = (List<Integer>)bar; // unchecked cast
// now there is a type mismatch
我正在阅读 OCaml 和 wiki,它说:
*its static type system renders runtime type mismatches impossible*
我明白为什么,但后来我想,为什么这在 OCaml(和 FP)中如此特别?您如何导致 Java 中的运行时类型不匹配?例如
boolean a = true;
int b = a + 1;
会return编译时出错。
编辑 1:
Haskell
func :: Int -> Bool
func i = if i > 0 then True else False
Java
boolean func (int i) {
if (i > 0) return true; else return false;
}
是不是在调用func
时两者都保证参数类型?
在 Java 中,您可以像这样导致运行时类型不匹配:
Object i = Integer.valueOf(6);
String s = (String) i;
System.out.println(s);
这将编译,因为 i
(Object
) 的编译时类型允许转换为 String
,但是在运行时,[= 的实际值11=](6
,因为 Integer
)将与 String
不兼容。
鉴于此,ClassCastException
被抛出。
考虑以下使用数组的代码:
// create an array of strings
String[] strings = new String[10];
// cast it to an array of objects
Object[] objects = strings;
// insert an object into the array
objects[0] = new Object(); // Run-time error occurs here
Java 允许编译,尽管将字符串数组转换为对象数组会引入 运行 时间错误的可能性。第 8 行演示了这一点,导致了 运行 次异常,该异常是专门为这种情况创建的类型:java.lang.ArrayStoreException: java.lang.Object
。
在 Java 中,类型可能不匹配。例如,以下抛出 ClassCastException
.
Object o = 1;
String s = (String) o;
但是,传递给方法的参数由编译器检查。
无法调用带有签名的方法
boolean func (int i)
除非i
是一个int
,并且不可能调用带有签名的方法
boolean func2 (String s)
除非 s
是 String
或 null
。
因此,您永远不会在运行时在 func2
的主体内获得 ClassCastException
,因为 s
不是 String
。
该 wiki 正在大体上讨论静态类型系统,并将它们与动态类型语言而不是其他静态类型语言进行对比。 OCaml 或 Haskell 没有关于不适用于所有静态类型语言的运行时类型不匹配的特定内容。
请注意,不可能有点虚伪。几乎所有静态类型语言都让您能够以有限的方式进行运行时类型化,因为如果没有它,某些任务将非常困难。事实上,您引用的那一段就列出了其中的几个案例,例如序列化。这里的其他答案在 Java 中提供了一些很好的例子。但是,绝大多数代码应该能够轻松避免运行时类型不匹配。
在Java中,不可能在可具体化类型(原始类型、非泛型引用类型、原始类型、所有参数化类型)之间存在类型不匹配通配符,或元素类型可具体化的数组类型)。
如果你有一个可具体化类型的变量,那么它在任何时间点持有的值都保证是该类型的值。对于引用类型,这意味着引用要么为空,要么指向一个对象,其运行时 class 是变量类型的子类型。这是有保证的,因为 Java 在存储类型不是变量类型的子类型的值时需要强制转换,并且向可具体化类型的强制转换是 checked 强制转换,这意味着它们是在运行时检查,如果类型不兼容,它将抛出异常而不是让类型不匹配。
另一方面,对于不可具体化的类型(例如参数化类型),可能存在类型不匹配(在[中称为"heap pollution" =26=] 术语)。这是因为对不可具体化类型的强制转换是 未经检查的强制转换.
List<String> foo = new ArrayList<String>();
foo.add("hi");
List<?> bar = foo;
List<Integer> baz = (List<Integer>)bar; // unchecked cast
// now there is a type mismatch