gpt4 book ai didi

java - Class.as子类签名

转载 作者:太空狗 更新时间:2023-10-29 22:39:46 24 4
gpt4 key购买 nike

我的问题很理论化...这是 Class.asSubclass ( Javadoc ) 的签名:

public <U> Class<? extends U> asSubclass(Class<U> clazz)

为什么在返回类型中使用通配符泛型?根据我对泛型的理解,更好的签名可能是:

public <U> Class<U> asSubclass(Class<U> clazz)

因为你肯定可以投

Class<? extends U>

更简单

Class<U>

Bloch 在他的书“Effective Java”中推荐(第 137 页,第 28 项):

Do not use wildcard types as return types. Rather than providing additional flexibility for your users, it would force them to use wildcard types in client code.

这个选择背后的原因是什么?我缺少什么?非常感谢您。

编辑:正如@egelev 所建议的那样,我确实可以用另一种方式来表达我的问题……事实上,“按原样”返回输入参数是没有意义的。所以真正的问题是:与普通转换相比,Class.asSubclass 方法的真正用途是什么?如果出现转换问题,两者都会抛出 ClassCastException。

可能添加它是为了避免在特定情况下未经检查的强制转换:当您将 asSubclass 方法的结果直接传递给另一个要求约束类型参数的方法时,如此处(取自 Effective Java,第 146 页):

AnnotatedElement element;
...
element.getAnnotation(annotationType.asSubclass(Annotation.class));

上述方法的签名是:

<T extends Annotation> T getAnnotation(Class<T> annotationClass);

在我看来,asSubclass 方法只是一种在没有适当的编译器警告的情况下执行(实际上!)未经检查的转换的方法...

这最终又重新提出了我之前的问题:签名

public <U> Class<U> asSubclass(Class<U> clazz)

会同样有效(即使奇怪,我承认)!它将与 getAnnotation 示例完全兼容,并且不会限制客户端代码迫使它使用毫无意义的通配符泛型。

编辑2:我想我的一般问题已经解决了;非常感谢您。如果有人有其他关于 asSubclass 签名正确性的好例子,请将它们添加到讨论中,我希望看到一个使用带有我的签名的 asSubclass 的完整示例,显然不起作用。

最佳答案

如果返回类型为Class<? extends U> .让我们先尝试理解,getClass签名:

AbstractList<String> ls = new ArrayList<>();
Class<? extends AbstractList> x = ls.getClass();

现在编译器允许我们这样做:

Class<AbstractList> x = ls.getClass();

这是错误的。因为在运行时,ls.getClass将是 ArrayList.class而不是 AbstractList.class . ls.getClass 也不能返回 Class<ArrayList>因为ls是 AbstractList<> 类型而不是 Arraylist

所以编译器现在说 - 好的!我不能返回Class<ArrayList>我也不能返回 Class<AbstractList> .但是因为我知道ls肯定是一个 AbstractList,所以实际的类对象只能是 AbstractList 的子类型。所以Class<? extends AbstractList>是一个非常安全的赌注。由于通配符:你不能做:

AbstractList<String> ls = new ArrayList<>();
Class<? extends AbstractList> x = ls.getClass();
Class<ArrayList<?>> xx = x;
Class<AbstractList<?>> xxx = x;

同样的逻辑适用于你的问题。假设它被声明为:

 public <U> Class<U> asSubClass(Class<U> c)

下面会编译:

 List<String> ls = new ArrayList<>();
Class<? extends List> x = ls.getClass();
Class<AbstractList> aClass = x.asSubclass(AbstractList.class); //BIG ISSUE

以上aClass在运行时是 Class<Arraylist>而不是 Class<AbstractList> .所以这不应该被允许!! Class<? extends AbstractList>是最好的选择。



我看到这个问题的第一个想法是,为什么不将其声明为:

 public <U extends T> Class<? extends U> asSubClass(Class<U> c)

对我可以传递的参数进行编译时限制更有意义。但我认为它不是首选的原因是——这会破坏 pre-java5 代码的向后兼容性。例如,如果 asSubClass,使用 pre-Java5 编译的代码将不再编译。如上所示声明。

Class x = List.class.asSubclass(String.class); //pre java5
// this would have not compiled if asSubclass was declared above like

快速检查:

    public static <T, U extends T> Class<? extends U> asSubClaz(Class<T> t, Class<U> c){
return t.asSubClass(c);
}
public static <T, U> Class<? extends U> asSubClazOriginal(Class<T> t, Class<U> c){
return t.asSubClass(c);
}
asSubClazOriginal(List.class, String.class);
asSubClaz(List.class, String.class); //error. So would have broken legacy code

PS:对于编辑过的问题,关于为什么 asSubClass而不是 Actor ? - 因为 Actor 是背叛。例如:

List<String> ls = new ArrayList<>();
Class<? extends List> x = ls.getClass();
Class<AbstractList> aClass = (Class<AbstractList>) x;

上面总是会成功,因为泛型被删除了。所以它的类(class)投给了一个类(class)。但是aClass.equals(ArrayList.class)会给假的。所以肯定 Actor 是错误的。如果你需要类型安全,你可以使用 asSubClaz以上

关于java - Class.as子类签名,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28604179/

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