gpt4 book ai didi

java - 类型删除后何时转换函数的通用返回值?

转载 作者:搜寻专家 更新时间:2023-10-30 19:46:57 24 4
gpt4 key购买 nike

这个问题是由 this StackOverflow question about unsafe casts: Java Casting method without knowing what to cast to 提出的.在回答问题时,我遇到了这种行为,我无法仅根据规范进行解释

我在 The Java Tutorials 找到了下面的语句Oracle 文档:

没有解释“如有必要”的确切含义,并且我在 Java LanguageSpecification 中发现没有提及这些类型转换完全没有,所以我开始尝试。

让我们看下面这段代码:

// Java source
public static <T> T identity(T x) {
return x;
}
public static void main(String args[]) {
String a = identity("foo");
System.out.println(a.getClass().getName());
// Prints 'java.lang.String'

Object b = identity("foo");
System.out.println(b.getClass().getName());
// Prints 'java.lang.String'
}

javac编译,用the Java Decompiler反编译:

// Decompiled code
public static void main(String[] paramArrayOfString)
{
// The compiler inserted a cast to String to ensure type safety
String str = (String)identity("foo");
System.out.println(str.getClass().getName());

// The compiler omitted the cast, as it is not needed
// in terms of runtime type safety, but it actually could
// do an additional check. Is it some kind of optimization
// to decrease overhead? Where is this behaviour specified?
Object localObject1 = identity("foo");
System.out.println(localObject1.getClass().getName());
}

我可以看到在第一种情况下有一个确保类型安全的转换,但在第二种情况下,它被省略了。这是当然可以,因为我想将返回值存储在 Object 中类型变量,因此根据类型安全性,强制转换不是绝对必要的。然而,它会导致不安全转换的有趣行为:

public class Erasure {
public static <T> T unsafeIdentity(Object x) {
return (T) x;
}

public static void main(String args[]) {
// I would expect c to be either an Integer after this
// call, or a ClassCastException to be thrown when the
// return value is not Integer
Object c = Erasure.<Integer>unsafeIdentity("foo");
System.out.println(c.getClass().getName());
// but Prints 'java.lang.String'
}
}

编译和反编译后,我没有看到类型转换以确保在运行时返回正确的类型:

// The type of the return value of unsafeIdentity is not checked,
// just as in the second example.
Object localObject2 = unsafeIdentity("foo");
System.out.println(localObject2.getClass().getName());

这意味着如果一个通用函数应该返回一个给定的对象类型,不能保证它最终返回该类型。一个使用上述代码的应用程序将在它尝试的第一点失败将返回值转换为 Integer 如果它确实这样做了,所以我觉得它打破了 fail-fast principle .

编译器插入此强制转换的确切规则是什么确保类型安全的编译以及这些规则在哪里指定?

编辑:

我看到编译器不会深入研究代码并尝试证明通用代码确实返回了它应该返回的内容,但它可以插入一个断言,或者至少是一个类型转换(它已经在特定情况下这样做了,如第一个示例所示)以确保正确的返回类型,因此后者将抛出 ClassCastException:

// It could compile to this, throwing ClassCastException:
Object localObject2 = (Integer)unsafeIdentity("foo");

最佳答案

如果你在规范中找不到它,那就意味着它没有被指定,并且由编译器实现来决定在哪里插入强制转换,只要被删除的代码满足非类型安全规则-通用代码。

在这种情况下,编译器删除的代码如下所示:

public static Object identity(Object x) {
return x;
}
public static void main(String args[]) {
String a = (String)identity("foo");
System.out.println(a.getClass().getName());

Object b = identity("foo");
System.out.println(b.getClass().getName());
}

在第一种情况下,在删除的代码中强制转换是必要的,因为如果删除它,删除的代码将无法编译。这是因为 Java 保证在运行时保存在可具体化类型的引用变量中的必须是 instanceOf 可具体化类型,所以这里需要进行运行时检查。

在第二种情况下,删除的代码无需转换即可编译。是的,如果您添加了类型转换,它也会编译。所以编译器可以决定任何一种方式。在这种情况下,编译器决定不插入强制转换。这是一个完全正确的选择。您不应该依赖编译器来决定任何一种方式。

关于java - 类型删除后何时转换函数的通用返回值?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34562435/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com