你能解释一下为什么//(?!)没有在行中抛出 ClassCastExeption 异常吗?There (T)is , where T=String, 这意味着 there (String) new Integer(42), 应该抛出异常...... JVM 应该转换类型,但由于某种原因它没有。然后我们看看类型t,看看Integer什么是真正的类型t。但是我们推断类型的事实表明没有抛出异常。然后程序在调用函数的地方抛出异常A.<String>f()。
顺便一提!我记得 Bruce Eckel 教过有一些 javap 反编译器,他自己使用字节码或 .class 编写程序代码……我没有研究它。如果有人精通这一点,请尝试让反编译器构建这段代码,也许它会显示那里真正发生了什么,为什么?
public class A {
public static <T> T f() {
T t = (T) new Integer(42); // (?!) ЧТО ЧЁРТ ВОЗЬМИ ЗДЕСЬ ВООБЩЕ ПРОИСХОДИТ?!
System.out.println(t.getClass());
return t;
}
public static void main(String[] args) {
System.out.println(A.<String>f()); // как здесь возможно исключение? ахаха, вы серьёзно?
}
}
新:
所以,朋友们。最常见的答案是,方法f()是已编译为常规方法的常规方法,但考虑到其调用结果被强制转换为传递为的类型这一事实<NameOfTheClass>。一切似乎都已经很好了,这个答案可以被接受,但如果它在 Java 中真的像这样工作......关键是你可以main(String[])尝试调用更具爆炸性的东西:
System.out.println(A.<Double>f());
令人惊讶的是,控制台会输出:
//output:
class java.lang.Integer
42
所以如果我们让它不可见,它看起来像这样:
System.out.println((Double)A.<Double>f());
然后尝试编译它 - 会出现错误啊哈哈哈,从那里得出的结论是它不能完全一样......
我对此的猜测是该方法println()被重载,并且在A.<String>f()它选择版本println(String arg)的情况下,并且在A.<Double>f()它理解Double没有版本并设置println(Object arg)它的情况下,因为对于我们的, 42 被(Object)Integer(42)调用.toString()并显示。
对我来说,奇怪的是,由于某种原因,在第一种情况下,当我们调用A.<String>f()它时,这里的许多人认为它是这样调用(String)A.<String>f()的,从它设置版本的位置开始println(String arg),而第二次调用时A.<Double>f(),它确实如此没有尝试这样做(Double)A.<Double>f(),它立即选择了println(Object arg)...。
您想说整个技术非常智能,如果println()成功检查参数化/泛型函数的返回是否作为重载方法中的参数存在,则不会调用强制转换[例如,String版本println()存在,是的,让我们将输出转换Object为A.f()指定的String],如果重载版本没有在类的类型参数中指定版本A.f(),println()那么它(编译器)离开版本println(Object)并决定不尝试(Object)(Double)A.<Double>f()做是结果f()本身Object吗?
总计:我想要解释参数化方法(类)是如何工作的,这样的解释是编译器对生成代码的操作的算法是清楚的。如果我对编译器操作的一些猜测是正确的,那么我希望他们(我的猜测)得到确认,并且非常希望(!)带有指向一些文档文件的链接!
运行时不存在泛型类型。这些只是编译时检查。
一切都还好。目的。
哎呀..没有字符串。这是例外。
结果是这样的:
编译过程中没有错误,但是执行时,第一个转换结果是 in
f并且它是有效的,但是第二个转换已经 inmain,它落在哪里。这是
main调用时的字节码A.<Double>f()这是
main调用时的字节码A<String>.f()注意这行
invokevirtual,第一种情况,调用带有签名的方法,println(Object o)第二种println(String s)情况-擦除Double类型后,方法返回,没有方法f(),Object里面平静println调用,一切正常美好的。在有一个方法的情况下,编译器决定需要调用它,所以那里有一个强制转换。DoubleDoubleprintlndoubleObjectString.valueOfStringprintlnString我包裹
System.out.println在我println的 3 种类型:而现在你已经猜到了当你打电话时会发生什么?
编译器将看到有一个重载
println的 forDouble并将强制转换(这就是错误所在):如果有不清楚的地方,您可以随时查看
bytecode:从代码中可以看出,该方法
f()并没有强制转换为String(显然,新对象所分配的引用类型将是Object)。但是在从参数化方法返回此对象的那一刻,发生了相同的强制转换,这就是发生异常的原因。泛型类型只能是非原始类型,即 最简单泛型的超类型是
Object. 这样上面的类只允许在自身内部调用变量上的
t类方法Object。那些。t类中所有代码的变量都是MyClass类型Object。ClassCastException这解释了将数字转换为对象时的缺失。但是如果我们更精确地指定泛型的类型,那么我们会得到一个编译错误(并且将无法到达运行时错误):
左右,然而,这是没有意义的,因为。
String- 最后一类(即“不育” - 它不能扩展,也不能有后代)类型推断的正确操作有不同的解释:
方法是
Java虚拟的。那些。不会调用类方法T(即Object在方法内),而是调用内存中特定类实现的方法Object。这已经是String,Integer等等。最终的运行时错误显然与码头中的示例相似,并且可以类似地重写代码,如下所示:
那些。你已经指出该方法应该返回一个字符串,调用该方法
System.out.println(String arg),将一个类型引用传递给它Object,它实际上存储了一个类型的对象Integer。并且在将存储在内存中的特定数字转换为字符串时,会发生异常