简体   繁体   English

强制转换由通用实例类型的 getClass() 返回的类在 Java 中总是安全的吗?

[英]Is casting the class returned by getClass() of a generic instance type always safe in Java?

I am not sure how to word the title of this question in a concise way.我不知道如何用简洁的方式来表达这个问题的标题。 There are a few related questions I have found, for instance this one , but none of them seem to answer the question I have explicitly.我发现了一些相关的问题,例如这个,但似乎没有一个能明确回答我提出的问题。

But essentially what I am asking is this:但基本上我要问的是:

Consider the following code考虑以下代码


static <A, B> Class<? extends A> getLeftClass(Pair<A, B> tuple) {
   A left = tuple.getLeft();
   return left.getClass();
}

As is, this code does not compile.按原样,此代码无法编译。 The compilation fails with the error Type mismatch: cannot convert from Class<capture#20-of ? extends Object> to Class<? extends A>编译失败并显示错误Type mismatch: cannot convert from Class<capture#20-of ? extends Object> to Class<? extends A> Type mismatch: cannot convert from Class<capture#20-of ? extends Object> to Class<? extends A>

I think this is essentially because getClass returns a type Class<? extends Object>我认为这本质上是因为getClass返回一个类型Class<? extends Object> Class<? extends Object> but the compiler is expecting Class<? extends A> Class<? extends Object>但编译器期待Class<? extends A> Class<? extends A> . Class<? extends A>

A solution is to cast the class as follows:一种解决方案是将类转换如下:


static <A, B> Class<? extends A> getLeftClass(Pair<A, B> tuple) {
   A left = tuple.getLeft();
   return (Class<? extends A>) left.getClass();
}

This compiles.这编译。 However, there is a warning because of an unchecked cast.但是,由于未经检查的强制转换,会出现警告。

My question is, is the warning justified?我的问题是,警告是否合理? Is there a legitimate reason not to do this?有正当理由不这样做吗? Or is this just a case where the compiler can't verify that it is correct, but it will always work as long as tuple.getLeft() is indeed an instance of A ?或者这只是编译器无法验证它是否正确的情况,但只要tuple.getLeft()确实是A的实例,它就会一直工作?


By the way, the Pair class is this one , from the Apache commons library顺便说一下, Pair类就是这个,来自 Apache 公共库

The warning is justified, as it allows in turn other unsafe operations that would not cause a warning.警告是合理的,因为它反过来允许其他不会导致警告的不安全操作。 The type parameter of Class allows you to perform dynamic runtime casts and instantiations and the type safety of those operations depends on the validity of the type parameter. Class的类型参数允许您执行动态运行时强制转换和实例化,这些操作的类型安全取决于类型参数的有效性。

In other words, your method allows the following operation:换句话说,您的方法允许以下操作:

Pair<List<String>,?> p = Pair.of(new ArrayList<>(), null);

List<Integer> listOfI = new ArrayList<>(Arrays.asList(1, 2, 3));
List<String> listOfS = getLeftClass(p).cast(listOfI);
listOfS.set(1, "foo");

This situation is called heap pollution and Java's generic type system guarantees that this situation can not occur with warning free source code.这种情况称为堆污染,Java 的泛型类型系统保证这种情况不会发生在无警告源代码中。 You get a warning and have the risk.您会收到警告并面临风险。

Likewise, we could do:同样,我们可以这样做:

List<String> stringList = getLeftClass(p)
    .getConstructor(Collection.class).newInstance(listOfI);
assert stringList.get(0) instanceof String;// will fail

There are similar 3rd party libraries, eg deserializers for XML or JSON, with similar assumptions about the type safety when being provided with a Class object as parameter to describe the assumed return type (or a component of the result).有类似的第 3 方库,例如 XML 或 JSON 的反序列化器,当提供Class对象作为参数来描述假定的返回类型(或结果的组成部分)时,它们对类型安全有类似的假设。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM