Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/336.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
从方法返回Java绑定的泛型对象_Java_Generics_Inheritance - Fatal编程技术网

从方法返回Java绑定的泛型对象

从方法返回Java绑定的泛型对象,java,generics,inheritance,Java,Generics,Inheritance,我知道Oracle教程和类似的问题,但仍然无法从Java方法返回泛型对象 简单示例:我有一个网络Packets的层次结构和一个Handlers的层次结构,参数化为它们处理的Packet。最后,我有一个Handlers注册表,其中包含一个方法,该方法将返回给定数据包的正确处理程序 我想实现所有这些,理想情况下没有手动抑制的警告 class Packet {} class ThisPacket extends Packet {} class ThatPacket extends Packet {}

我知道Oracle教程和类似的问题,但仍然无法从Java方法返回泛型对象

简单示例:我有一个网络
Packet
s的层次结构和一个
Handler
s的层次结构,参数化为它们处理的
Packet
。最后,我有一个
Handler
s注册表,其中包含一个方法,该方法将返回给定数据包的正确处理程序

我想实现所有这些,理想情况下没有手动抑制的警告

class Packet {}
class ThisPacket extends Packet {}
class ThatPacket extends Packet {}

interface PacketHandler<P extends Packet> {
    boolean handle(P p);
}

class ThisPacketHandler extends PacketHandler<ThisPacket> {
    boolean handle(ThisPacket p);
}

class ThatPacketHandler extends PacketHandler<ThatPacket> {
    boolean handle(ThatPacket p);
}
类数据包{}
类thispack扩展数据包{}
类ThatPacket扩展数据包{}
接口PacketHandler{
布尔句柄(P);
}
类ThisPacketHandler扩展了PacketHandler{
布尔句柄(thisp);
}
类ThatPacketHandler扩展PacketHandler{
布尔句柄(p);
}

这是非常规则的,我相信,在我的实现中,中间有一些抽象类来定义我的层次结构,但我认为现在可以忽略。 关键部分是i)注册表:

class HandlersRegistry {
    static <<RETURN TYPE>> getHandler(Packet p) {
        if (p instanceof ThisPacket) return new ThisPacketHandler();
        if (p instanceof ThatPacket) return new ThatPacketHandler();
        return null;
    }
}

<<RETURN TYPE>> OPTIONS (I tried):
    // Raw-type Warning:
    A. PacketHandler 
    // the registry user won't be able to use the handler:
    B. PacketHandler<? extends Packet>
    // Type mismatch: cannot convert from 
    C. PacketHandler<Packet> 
类句柄注册表{
静态getHandler(数据包p){
如果(ThisPacket的p instanceof)返回新的ThisPacketHandler();
如果(该数据包的p实例)返回新的ThatPacketHandler();
返回null;
}
}
选项(我尝试过):
//原始类型警告:
A.打包机
//注册表用户将无法使用处理程序:
B.PacketHandler在此处使用泛型没有意义:

  • 首先,您永远不知道编码时返回对象的类型,这没有带来任何好处
  • 其次,使用泛型会造成混淆(例如,对于case
    HandlerSwitchExample
    ,您不想使用对象类型
    T
因此,只需使用继承即可

PacketHandler handler = HandlersRegistry.getHandler(somePacket);

HandlersRegistry
中,您可以实现以支持不同类型的数据包


有了它,您可以在项目中增加更多的灵活性,因为您可以拥有任意数量的数据包类型和数据包处理程序,并且还可以隐藏真正的实现。还强制客户端仅使用您在接口中定义的公共API,从而限制您的风险。

您基本上有两个并行层次结构(
Packet
PacketHandler
),其中一个层次结构上的每个级别与另一个层次结构中的相同级别相关。下图显示了您的结构(跳过了ThatHandler的

这些情况通常使用自引用类型参数来解决。另外,使用工厂方法,而不是在注册表中创建对象

以下是您的类结构的变化(同时,我想您应该将
数据包
类抽象化:

abstract class Packet<T extends Packet<T>> {
  /**
   *  Factory method.
   *  Override this method in sub-packets to return appropriate handlers
   */
  abstract PacketHandler<T> getHandler();
}
最后,书记官处:

class HandlersRegistry {
  static <P extends Packet<P>> PacketHandler<P> getHandler(P p) {
    return p.getHandler();
  }
}
类句柄注册表{
静态PacketHandler

getHandler(P){ 返回p.getHandler(); } }

然后像这样使用它:

ThisPacket somePacket = new ThisPacket();
PacketHandler<ThisPacket> handler = HandlersRegistry.getHandler(somePacket);
handler.handle(somePacket);
thispack somePacket=newthispack();
PacketHandler=HandlersRegistry.getHandler(somePacket);
handler.handle(somePacket);

现在,使用上述结构,您可以继续添加新数据包,而无需修改现有的类。只需创建一个
Packet
和相应的
PacketHandler
。覆盖
getHandler()
方法,您可以很好地使用它。现在还需要更改注册表类。

不是类似于
static

PacketHandlergetHandler(p)

工作?我肯定误解了你的问题,但是=Packet和=Handler@biziclop:
类型不匹配:无法将此PacketHandler转换为PacketHandler

@m0skit0:如果您的意思是
=>>对象类型>>=PacketHandler
),则是,但我收到原始类型警告!这里的一个关键问题是,“用户”(将数据包传递到注册表的用户)是通过其冲突类型还是仅通过其基类型来了解数据包。如果他知道它的真实类型(也就是说,如果他有一个
ThisPackage p
,而不仅仅是一个
Package p
),那么这可能相当简单。但我假设情况并非如此(从变量名“some Package”猜测),不确定是谁否决了你的答案(不是我),希望他/她能给出解释。在我看来,您的解决方案是有道理的,但只要这个数据包和那个数据包共享一个共同点,这对于这个和那个处理程序来说就足够了,否则就需要显式转换@m0skit0没问题,您现在可以撤消:)(刚刚编辑了我的答案)天哪。。谢谢我想我会尝试这个可爱的讨厌的模式,但只有一个问题:如果注册表用户从另一个方法
packet getPacket()
获取数据包,那么所有这些混乱(包括我的和Pham的)都不会解决,因为接收到的数据包,无论是什么子类型,都会被擦除到其上限@Campa泛型的问题是,要使它与其他事物一起工作,你必须使其他事物也通用。因此,您的
getPacket()
方法也应该是泛型的。您将如何实现它取决于您将在何处使用该方法。但理想情况下,您的注册表应该只创建一个对象,要么是处理程序,要么是数据包。很难从简短的高级描述中做出判断,但是如果结构是按照类名的建议进行的,然后让
创建自己的
处理程序
从OOD的角度来看,对我来说是一个可怕的想法(顺便说一句,这会使注册表有些多余…@Marco13在这种情况下,注册表是多余的,我可以很高兴地放弃它。不知道为什么这个解决方案是可怕的:有其他的想法吗?@Campa可能“可怕”太强烈了-从某种意义上说,它“似乎不正确”。参考设计,您应该看到缺点:对于同一类型,不能有不同类型的
PackageHandler
abstract class Packet<T extends Packet<T>> {
  /**
   *  Factory method.
   *  Override this method in sub-packets to return appropriate handlers
   */
  abstract PacketHandler<T> getHandler();
}
class ThisPacket extends Packet<ThisPacket> {
  @Override
  PacketHandler<ThisPacket> getHandler() {
    return new ThisPacketHandlerImpl();
  }
}

class ThatPacket extends Packet<ThatPacket> {
  @Override
  PacketHandler<ThatPacket> getHandler() {
    return new ThatPacketHandlerImpl();
  }
}
interface PacketHandler<P extends Packet<P>> {
  boolean handle(P p);
}

class ThisPacketHandlerImpl implements PacketHandler<ThisPacket> {
  @Override
  public boolean handle(ThisPacket p) {
    return false;
  }

}

class ThatPacketHandlerImpl implements PacketHandler<ThatPacket> {
  @Override
  public boolean handle(ThatPacket p) {
    return false;
  }
}
class HandlersRegistry {
  static <P extends Packet<P>> PacketHandler<P> getHandler(P p) {
    return p.getHandler();
  }
}
ThisPacket somePacket = new ThisPacket();
PacketHandler<ThisPacket> handler = HandlersRegistry.getHandler(somePacket);
handler.handle(somePacket);