当前位置: 首页 > 面试题库 >

Java Generics进行奇怪的转换

柴瀚
2023-03-14
问题内容

这个问题已经在这里有了答案

为什么对泛型的这种使用不会引发运行时或编译时异常? (3个答案)

2年前关闭。

我正在使用Java 8。

我最近遇到了这个问题:

public class Test {
    public static void main(String[] args) {
        String ss = "" + (Test.<Integer>abc(2));
        System.out.println(Test.<Integer>abc(2));
    }
    public static <T> T abc(T a) {
        String s = "adsa";
        return (T) s;
    }
}

这不会引发java.lang.ClassCastException。这是为什么?

我一直在想+System.out.println打电话toString。但是,当我尝试这样做时,它会按预期抛出异常。

String sss = (Test.<Integer>abc(2)).toString();

问题答案:

它不会抛出,ClassCastException因为所有通用类型信息都已从编译后的代码中剥离(此过程称为类型擦除)。基本上,任何类型参数都由代替Object。这就是第一个版本起作用的原因。这也是代码完全编译的原因。如果您要求编译器通过-Xlint:unchecked标记警告未经检查的操作或不安全的操作,则会在的return语句中收到有关未经检查的强制转换的警告abc()

带有以下语句:

String sss = (Test.<Integer>abc(2)).toString();

故事有点不同。当type参数T替换为时Object调用代码将转换为字节代码,该字节代码将结果显式转换为Integer。就像代码是使用带有签名的方法编写的,static Object abc(Object)并且语句是这样编写的:

String sss = ((Integer) Test.abc(Integer.valueOf(2))).toString();

也就是说,内部abc()类型转换不仅会由于类型擦除而消失,而且编译器还会在调用代码中插入新的类型转换。该强制类型转换ClassCastException在运行时生成a
,因为从返回的对象abc()String,而不是Integer

注意声明

String ss = "" + (Test.<Integer>abc(2));

不需要强制转换,因为编译器只是将返回的对象提供给对象abc()的字符串连接操作。(有关此操作的详细信息随Java编译器的不同而不同,但这是对StringBuilderappend方法的调用,或者,从Java
9开始,是对StringConcatFactory。创建的方法的调用。)这里的细节无关紧要;关键是编译器足够聪明,可以识别出不需要强制转换。



 类似资料:
  • 我有以下代码来解析一个JSON文件: 要处理以下JSON文件: 如果我执行此代码,我将收到以下错误: 所以我开始一步一步地调试应用程序,看看part processing()中的哪个代码部分抛出了这个异常。令人惊讶的是,那里的所有代码都正常执行:没有抛出异常,也没有返回结果I except。 更让我惊讶的是,当我稍微改变第一种方法的代码时,它可以在不产生异常的情况下工作。 我不知道println方

  • 我遇到了奇怪的问题时,铸造小数到双倍。 以下代码返回true: 但是,当我将其强制转换为双倍时,它返回false: 这是记录在案的行为吗?当我被迫将decimal转换为Double时,我如何避免它? Visual Studio的截图: 将Math.round铸造为双倍me,结果如下: null 不幸的是,我不能在较小的项目中重现这个问题。我想埃里克的回答解释了原因。

  • 问题内容: 我在GregorianCalendar类中遇到一个奇怪的行为,我想知道我是否真的做得不好。 仅当初始化日期的月份的实际Maximum大于我将日历设置为的月份时,才追加此值。 这是示例代码: 我知道问题是由于日历初始化日期是31天(可能是5月),与设置为2月(28天)的月份混淆了。修复很容易(只需在设置年和月之前将day_of_month设置为1),但是我想知道这确实是想要的行为。有什么

  • 问题内容: 我正在为一个问题而苦苦挣扎,我不明白为什么它不起作用。如何通过将变量传递并转换为? 为什么在顶部代码段中不起作用,但在行下方的底部代码段中起作用? 唯一的区别似乎是添加了一个额外的变量,该变量也被键入为? 问题答案: 该是一种原始类型,同时是一个普通的Java类。您不能在原始类型上调用方法。但是该方法在上可用,如javadoc中所示 有关这些原始类型的更多信息,请参见此处

  • 问题内容: 为什么的到哪里去了? 问题答案: 删除任何字符,并从字符串的开头和结尾。

  • 问题内容: 我认为这是一个正常程序,但这是我得到的输出: 有人可以向我解释一下吗? 问题答案: 这是有据可查的PHP行为,请参阅php.net的foreach页面上的警告。 警告 即使在 foreach 循环之后,仍保留 $ value的 引用和最后一个数组元素。建议通过unset()销毁它。 __ 编辑 尝试逐步了解此处实际发生的情况