Java 具有另一个泛型类作为参数的泛型类
我发现自己在使用泛型时遇到了一种奇怪的情况,到目前为止,这似乎是不可能的。我试着在简单的课堂上孤立这种情况。我试图实现的是:一个分派句柄以处理数据包的服务类。每个处理程序都有一个数据包类型参数,因为每个数据包都应该有一个处理程序。服务类还有一个Handler type参数,因为有几种类型的处理程序,所以不同的处理程序类型需要几种服务。这个描述可能不是很清楚,所以我举了一个例子:Java 具有另一个泛型类作为参数的泛型类,java,generics,nested-generics,Java,Generics,Nested Generics,我发现自己在使用泛型时遇到了一种奇怪的情况,到目前为止,这似乎是不可能的。我试着在简单的课堂上孤立这种情况。我试图实现的是:一个分派句柄以处理数据包的服务类。每个处理程序都有一个数据包类型参数,因为每个数据包都应该有一个处理程序。服务类还有一个Handler type参数,因为有几种类型的处理程序,所以不同的处理程序类型需要几种服务。这个描述可能不是很清楚,所以我举了一个例子: public abstract class Service<T extends Handler<?>
public abstract class Service<T extends Handler<?>> {
//Some random logic
//If only I could use T<E>
protected abstract <E extends Packet> void handle(T handler, E packet);
}
public class ServiceImpl extends Service<HandlerOne<?>> {
@Override
protected <E extends Packet> void handle(HandlerOne<?> handler, E packet) {
handler.handle("someString", packet); //ERROR
}
}
public interface Handler<E extends Packet> {
}
public interface HandlerOne<E extends Packet> extends Handler<E> {
void handle(Object someObject, E packet);
}
public class HandlerOneImpl implements HandlerOne<SomePacket> {
@Override
public void handle(Object someObject, SomePacket packet) {
}
}
public interface Packet {
}
public class SomePacket implements Packet {
}
公共抽象类服务>{
@凌驾
受保护的无效句柄(HandlerOne句柄,E数据包){
handle.handle(“someString”,数据包);//错误
}
}
公共接口处理程序{
}
公共接口HandlerOne扩展处理程序{
无效句柄(objectsomeobject,E数据包);
}
公共类HandlerOneImpl实现HandlerOne{
@凌驾
公共无效句柄(对象someObject,SomePacket){
}
}
公共接口包{
}
公共类SomePacket实现数据包{
}
有没有办法完成这样的事情,或者有什么建议?谢谢
编辑:这是manouti答案中修改过的代码(注意:为了清晰起见,我将SomePacket改为PacketOne)。我遇到的问题是创建ServiceImpl的疯狂
public static void main(String[] args) {
HashMap<Class<? extends Packet>, HandlerOne<? extends Packet>> handlerMap = new HashMap<>();
handlerMap.put(PacketOne.class, new HandlerOneImpl());
ServiceImpl<Packet, HandlerOne<?>> s = new ServiceImpl<>(handlerMap);//ERROR
}
public static abstract class Service<E extends Packet, T extends Handler<E>> {
Map<Class<? extends Packet>, T> handlerMap;
public Service(Map<Class<? extends Packet>, T> handlerMap) {
this.handlerMap = handlerMap;
}
//Some random logic
//If only I could use T<E>
protected abstract void handle(T handler, E packet);
}
public static class ServiceImpl<E extends Packet, T extends HandlerOne<E>> extends Service<E, T> {
public ServiceImpl(Map<Class<? extends Packet>, T> handlerMap) {
super(handlerMap);
}
@Override
protected void handle(T handler, E packet) {
handler.handle("someObject", packet);
}
}
publicstaticvoidmain(字符串[]args){
HashMap>s=newServiceImpl(handlerMap);//错误
}
公共静态抽象类服务{
Map方法句柄
需要一个对象
和一个类型为E
的参数(类型参数)。您只指定了第二个
然后,由于?
通配符的捕获转换,即使在第一个参数中引入对象
,仍然会出现错误。因此,我将使用两个类型参数:
public abstract class Service<E extends Packet, T extends Handler<E>> {
// Some random logic
protected abstract void handle(T handler, E packet);
}
public class ServiceImpl<E extends Packet, T extends HandlerOne<E>> extends Service<E, T> {
@Override
protected void handle(T handler, E packet) {
handler.handle(new Object(), packet); // some object as first parameter
}
}
公共抽象类服务{
//一些随机逻辑
受保护的抽象无效句柄(T句柄、E包);
}
公共类ServiceImpl扩展了服务{
@凌驾
受保护的无效句柄(T处理程序、E数据包){
handle.handle(new Object(),packet);//将某个对象作为第一个参数
}
}
当前代码的问题在于以下语句:
protected <E extends Packet> void handle(HandlerOne<?> handler, E packet) {
handler.handle("someString", packet); //ERROR
}
受保护的无效句柄(HandlerOne句柄,E数据包){
handle.handle(“someString”,数据包);//错误
}
您正在告诉处理程序,该处理程序被键入“some”数据包类型,用于处理E
类型的数据包。在运行时,处理程序的实际数据包类型可能不是E
您遇到了Java类型系统的限制,要正确地做到这一点,您需要类似的东西。Java不支持这一点,我见过的最接近实现的是(实验性)项目。HighJ使用见证类型来分离容器和值类型。例如,从它们的
我发现在Java中模拟高阶类型多态性的唯一方法是使用我们已有的抽象,即类型参数的抽象。要做到这一点,我们需要将“容器类型”从其值类型中分离出来,然后将其本身作为类型参数。所以
列表我们有类似
某物
但是,在生产(Java)项目上这样做可能不是一个好主意,因为它很复杂,学习曲线很陡。我建议您在某个地方简化设计
更高种类的类型(泛型上的泛型)允许更高级别的抽象(你可以说
List<T extends Processor<E>>
列表
例如),为了使设计更简单,您可以牺牲抽象(在某处复制一些代码),也可以牺牲类型安全(动态语言与具有高级类型系统的语言一样简洁)
您可以通过额外的单元测试来弥补类型安全性方面的损失。我看到的第一件事是:您试图调用句柄,期望两个参数只给出一个。@Jean-FrançoisSavard Oops,是的,我的错。这是一个错误,但我无法找出的主要错误是让服务中的处理程序和数据包对齐。是否有多个不同的类型添加到HashMap中,然后传递给ServiceImpl?因为看起来您试图让该类在内部处理多个类型,但只提供一个(更高级的类型)外部类型视图?@JohnMcClean是的,这就是我试图实现的。你能解释一下原因吗?因为如果服务实际上处理多个类型,它没有一个类型可以公开。删除高阶泛型会使事情变得更简单吗?例如类服务?我认为没有一个类型e或t包含数据包和手是的。我尝试了一些类似的方法,现在已经接近解决方案了,但它引入了另一个问题。ServiceImpl类必须处理HandlerOne的几个实现,所有这些实现都有不同的数据包实现参数。我想这将使创建新的ServiceImpl成为不可能。@stripes I d我不知道这将如何阻止它处理不同的HandlerOne
实现。您能提供一个问题示例吗?
List<T extends Processor<E>>