下面的SCCE显示了实现接口标记的2个类(B和C)。对于实现Marker的每个类,都有一个实现泛型Handler接口(B_Handler,C_Handler)的相应类。映射用于将Pair.second的Class类型与其关联的Handler相关联。代码按预期执行;但是,我得到了一个编译时警告:
警告:[未选中]未经检查的强制转换 处理程序h1 =(处理程序)(dispatch.get(p1.second.getClass())); 必需:处理程序 发现:处理程序 其中CAP#1是一个新的类型变量: CAP#1扩展了Marker的捕获?扩展标记
除了@SuppressWarnings(value =“unchecked”)之外,最简单的解决方法是什么?
package genericpair;
import java.util.HashMap;
import java.util.Map;
import javax.swing.SwingUtilities;
public class GenericPair
{
public class A
{
}
public interface Marker
{
}
public class B implements Marker
{
}
public class C implements Marker
{
}
public Pair<A, Marker> getTarget()
{
A a = new A();
C c = new C();
return new Pair<>(a, c);
}
public interface Handler<T extends Marker>
{
void handle(Pair<A, T> target);
}
public class B_Handler implements Handler<B>
{
@Override
public void handle(Pair<A, B> target)
{
System.out.println("B");
}
}
public class C_Handler implements Handler<C>
{
@Override
public void handle(Pair<A, C> target)
{
System.out.println("C");
}
}
public class Pair<F, S>
{
public final F first;
public final S second;
public Pair(F first, S second)
{
this.first = first;
this.second = second;
}
}
private void executeSCCE()
{
// register a handler for each Marker type
Map<Class, Handler<? extends Marker>> dispatch = new HashMap<>();
dispatch.put(B.class, new B_Handler());
dispatch.put(C.class, new C_Handler());
// get a target (e.g., Pair<A,C>)
Pair<A, Marker> p1 = getTarget();
// select handler based on the class type of the second parameter
Handler<Marker> h1 = (Handler<Marker>) (dispatch.get(p1.second.getClass()));
h1.handle(p1);
}
public static void main(String[] args)
{
SwingUtilities.invokeLater(() -> new GenericPair().executeSCCE());
}
}
答案 0 :(得分:4)
考虑以下示例:
List<? extends List> test1 = new ArrayList<>();
List<List> test2 = (List<List>) test1;
我们收到警告:
warning: [unchecked] unchecked cast
List<List> test2 = (List<List>) test1;
^
required: List<List>
found: List<CAP#1>
where CAP#1 is a fresh type-variable:
CAP#1 extends List from capture of ? extends List
这是因为无法确保List<List>
的通用约束与List<? extends List>
匹配。想象一下,我们将此示例重写为以下内容:
List<? extends List> test1 = new ArrayList<ArrayList>();
List<List> test2 = (List<List>) test1;
test1.add(new LinkedList<>());//ERROR no suitable method found for add(LinkedList<Object>)
test2.add(new LinkedList<>());//Will work fine!!
这里更明显的是初始合同被打破了。定义为包含ArrayList
的列表现在包含LinkedList
。这是不安全的,这也是您收到此警告的原因。因此,无法安全地从Handler<? extends Marker>
投射到Handler<Marker>
。
答案 1 :(得分:1)
有几个问题。
首先,您的Map
无法表达每个密钥与其值之间的类型关系。因此,如果您将Class<T>
传递给dispatch.get()
,则只会返回Handler<? extends Marker>
,而不是Handler<T>
。事实上,没有任何类型可以让dispatch
来完成这项工作。相反,您必须创建一个包装类来通过其API强制执行此关系:
public class ClassToHandlerMap
{
private final Map<Class<?>, Handler<?>> map = new HashMap<>();
public <T extends Marker> void put(Class<T> clazz, Handler<T> handler) {
map.put(clazz, handler);
}
@SuppressWarnings("unchecked")
public <T extends Marker> Handler<T> get(Class<T> clazz) {
return (Handler<T>)map.get(clazz);
}
}
请注意,您仍然必须在此课程中禁止未经检查的警告,但至少在此您知道它可以证明是正确的,具体取决于如何将内容放入地图中。未经检查的演员表只是该类用户不需要了解的实现细节。
第二个问题是getTarget()
可能应该返回Pair<A, ? extends Marker>
而不是Pair<A, Marker>
。你没有Handler
的{{1}};相反,您有Marker
个特定类型的Handler
。因此,您只使用Marker
特定类型的Pair
也是有道理的。
Marker
你的函数的最后一部分主要是使用public Pair<A, ? extends Marker> getTarget()
{
A a = new A();
C c = new C();
return new Pair<>(a, c);
}
来操作它自己,所以我们需要使用一个捕获帮助器来捕获&#34; p1
类型中的?
为我们需要做的有用类型变量。
但是,在这种情况下,这更复杂,因为您使用的是p1
。 .getClass()
的类型为foo.getClass()
,其中Class<? extends |X|>
是编译时类型|X|
的删除。因此,无论foo
类型p1
还是Pair<A, ?>
,Pair<A, T>
仍会返回类型p1.second.getClass()
。因此,捕获Class<? extends Marker>
中的?
是不够的;相反,我们应该在Pair<A, ?>
:
?
.getClass()
不幸的是,我们还必须在此处进行未经检查的演员表。由于@SuppressWarnings("unchecked")
private static <T extends Marker> void captureHelper(Class<T> clazz,
Pair<A, ? extends Marker> p, ClassToHandlerMap dispatch) {
Pair<A, T> p1 = (Pair<A, T>)p;
Handler<T> h1 = dispatch.get(clazz);
h1.handle(p1);
}
的特殊返回类型,我们无法连接.getClass()
的返回类型及其被调用的表达式。并且我们不能像.getClass()
那样使用运行时强制转换来在参数化类型之间进行转换(如果我们将给定类的实例作为参数,我们可以使用.cast()
去除未经检查的强制类型转换,但不是这里)。可能存在一些不正确的边缘情况,但只要您始终使用.cast()
且第二个类型参数是最终实现类,它应该是正确的。
最后,主要方法如下所示:
Pair