我正在尝试创建一个 BufferedServerSocketImpl
,它将在 getInputStream
中返回一个 BufferedInputStream
而不是包装对象的非缓冲对象(markSupported()
=false),但否则只需将所有其他调用转发到包装的 SocketImpl 对象。
我遇到的问题是 accept
和其他 protected 抽象方法不可见。以下是摘录:
public class BufferedServerSocketImpl extends SocketImpl {
private SocketImpl internalSocketImpl;
BufferedServerSocketImpl(SocketImpl nested) {
this.internalSocketImpl = nested;
}
@Override
protected void accept(SocketImpl s) throws IOException {
internalSocketImpl.accept(s);
}
//...
}
在上面的示例中,internalSocketImpl.accept(s);
是一个错误,因为类型 SocketImpl
的方法 accept(SocketImpl)
是不可见。
我知道我要包装的对象将是 java.net.PlainServerSocketImpl
或 java.net.SocksSocketImpl
,但我无法将它们扩展为它们也不可见。
关于为什么会这样以及我如何解决这个问题有什么想法吗?
我考虑过对 Socket
或 SocketImpl
使用动态代理,但由于它们没有接口(interface),我必须使用外部库或进行字节码操作,两者都不是对于该项目来说是可行的。另外,我在 OSGi 框架中运行,因此类加载器恶作剧也不可行。
最佳答案
如果您找不到包含您想要委托(delegate)的所有方法的委托(delegate)对象的单个接口(interface)或抽象类,则将没有直接的方法来扩展或委托(delegate)(即使您不应该同时进行两者)(* )。
我只能想象两个选择:duck typing通过反射或多个接口(interface)使用。
在鸭子类型中,您永远不会想知道委托(delegate)是什么类或它实现什么接口(interface),您只需要它有一个具有给定名称和参数类型的方法,然后通过反射获得它
Method method = internalSocketImpl.getClass.getMethod("accept", SocketImpl.class);
method.invoke(internalSocketImpl, s);
它实现起来很简单,但会影响性能,并且您会失去对可访问方法的所有编译时控制。您必须从 getMethod
捕获异常。 ( NoSuchMethodException
) 和 invoke
(IllegalAccessException
、IllegalArgumentException
、InvocationTargetException
)
<TL/DR mode>
在使用多个接口(interface)/父类(super class)时,您传递一个实现一个接口(interface)/父类(super class)的对象,并且您在文档中声明它必须还实现/扩展其他接口(interface)/父类(super class)。编译器无法帮助您控制这一点,但是只要实现/扩展了接口(interface)/父类(super class),它就应该可以工作:
ServerSocket server = (ServerSocket) internalSocketImpl;
server.accept(s);
它更干净,但您必须找到一组接口(interface)或父类(super class),其中包含您需要的所有方法以及由任何可能的委托(delegate)实现/扩展的方法。您必须测试 ClassCastException
.
如果在之前的用例中,所有方法都可以在接口(interface)中找到,则最后一个选项可用,它是代理。您无需创建新类,只需为您的委托(delegate)获取一个代理。但我不会再详细说明,因为方法accept
的ServerSocket
不存在于 ServerSocket
实现的任何方法中.
</ TL/DR mode>
这是针对一般情况的,但在您的实际情况中,我认为您应该使用不同的子类,每个子类对应您想要扩展的每个 SocketImpl 子类,而应使用您放入所有子类中的缓冲对象作为助手用于覆盖您需要的方法。这将避免扩展 + 委托(delegate)模式 (*)
(*) 您正在扩展SocketImpl
,这意味着您的类拥有 SocketImpl 所有字段的实例,并且不要使用它们,因为您将所有实际处理委托(delegate)给另一个对象 internalSocketImpl
。这就是其他人所说的混合继承和组合的意思。
关于java - protected 抽象方法在父类包装实例的子类中不可见,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26178168/