我试图创建一个BufferedServerSocketImpl
,它会在BufferedInputStream
中返回getInputStream
而不是包装对象中的非缓冲对象(markSupported()
= false),但只是简单地将所有其他调用转发给包装的SocketImpl对象。
我遇到的问题是accept
和其他受保护的抽象方法不可见。这是一个摘录:
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);
是一个错误,因为类型accept(SocketImpl)
中的方法SocketImpl
不可见。
我知道我要换的对象将是java.net.PlainServerSocketImpl
或java.net.SocksSocketImpl
,但我无法扩展它们,因为它们也不可见。
有关为何如此以及如何解决这个问题的任何想法?
我考虑过使用Socket
或SocketImpl
的动态代理,但由于它们没有接口,我必须使用外部库或进行字节码操作,这两种操作都不适用于项目。另外,我在OSGi框架中运行,因此类加载器的恶作剧也是不可行的。
答案 0 :(得分:1)
您正在尝试在班级中同时使用合成和继承。在我看来,这有点误导。
你应该做的是,只使用继承。
public class BufferedServerSocketImpl extends SocketImpl {
@Override
protected void accept(SocketImpl s) throws IOException {
super.accept(s);
}
//...
}
或者,如果您真的想使用合成,则可以声明您的类在同一个包中。然而,在我看来,这个类是一个抽象类的事实是一个强有力的指标,它不应该用于组合。
更好的方法,对于组合方法,将沿着继承层次结构向下走,直到找到合适的候选类。
答案 1 :(得分:1)
如果你找不到包含你想要委派的所有方法的委托对象的单个接口或抽象类,那么既没有直接的方式也不能用于委托(即使你不应该同时委托)(* )。
我只能想象两个选项:duck typing通过反射或多个接口使用。
在duck typing中,你永远不知道委托是什么类,它实现了什么接口,你只需要它有一个给定名称和参数类型的方法,你用反射得到它
Method method = internalSocketImpl.getClass.getMethod("accept", SocketImpl.class);
method.invoke(internalSocketImpl, s);
实现起来很简单,但是具有性能含义,并且您对可访问方法的所有编译时控制都失去了。您必须同时捕获getMethod
(NoSuchMethodException
)和invoke
(IllegalAccessException
,IllegalArgumentException
,InvocationTargetException
)
<TL/DR mode>
在多个接口/超类用法中,您传递一个实现一个的对象,并在文档中声明必须还实现/扩展其他对象。编译器无法帮助您控制它,但是如果实现/扩展接口/超类,它应该可以工作:
ServerSocket server = (ServerSocket) internalSocketImpl;
server.accept(s);
它更清晰,但您必须找到一组接口或超类,包含您需要的所有方法以及任何可能的委托实现/扩展的方法。您必须测试ClassCastException
。
如果在以前的用例中,所有方法都可以在接口中找到,那么最后一个选项是可用的,它是代理的。您只需将代理服务器委托给代理人,而不是创建新类。但我不会进一步详细说明,因为accept
的方法ServerSocket
在ServerSocket
实现的任何方法中都不存在。
</ TL/DR mode>
这是针对一般情况的,但在您的实际情况中,我认为您应该使用不同的子类,每个子类要扩展一个SocketImpl子类,而是使用一个缓冲对象,将您放在所有子类中作为帮助器用于覆盖您需要的方法。这样可以避免使用extend + delegate模式(*)
(*)您正在扩展SocketImpl
,这意味着您的类具有SocketImpl的所有字段的实例,并且不使用它们,因为您将所有实际处理委托给另一个对象internalSocketImpl
。这就是其他人所说的混合继承和组合的意思。
答案 2 :(得分:0)
你不能调用 internalSocketImpl.accept; s <; em>,你应该使用 super.accept; s
答案 3 :(得分:0)
这不是很安全,但你可以试试。
在eclipse上,如果you're configured to see the source code,双击SocketImpl获取其源代码。
然后在项目中创建一个包java.net并使用此源代码创建一个名为SocketImpl的类并打包java.net。
找到accept()方法,将其可见性更改为public。
也可以从BufferedServerSocketImpl更改它。
实现(新)抽象超类所需的所有其他方法。
请记住:您正在欺骗类加载器。小心。