Java 抽象访问者 - 保证成功吗?如果是这样,为什么?
我正在处理休眠,试图通过使用访问者模式找出代理实例背后的运行时类。然后我想出了一个 AbstractVisitable 方法,但我想知道它是否总是会产生正确的结果。
考虑以下代码:
interface Visitable {
public void accept(Visitor v);
}
interface Visitor {
public void visit(Visitable visitorHost);
}
abstract class AbstractVisitable implements Visitable {
@Override
public void accept(Visitor v) {
v.visit(this);
}
}
class ConcreteVisitable extends AbstractVisitable {
public static void main(String[] args) {
final Visitable visitable = new ConcreteVisitable();
final Visitable proxyVisitable = (Visitable) Proxy.newProxyInstance(
Thread.currentThread().getContextClassLoader(),
new Class<?>[] { Visitable.class }, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method,
Object[] args) throws Throwable {
return method.invoke(visitable, args);
}
});
proxyVisitable.accept(new Visitor() {
@Override
public void visit(Visitable visitorHost) {
System.out.println(visitorHost.getClass());
}
});
}
}
这使得 ConcreteVisitable
继承了 AbstractVisitable
的 accept
方法。在 C++ 中,我认为这是有风险的,因为 AbstractVisitable 中的 this
可能引用 AbstractVisitable::this
,而不是 ConcreteVisitable::this
。我担心代码在某些情况下会打印class AbstractVisible
。然而,上面的代码输出 class ConcreteVisitable
,即使我将真实类型隐藏在动态代理后面(我能想到的最困难的情况)。上面的抽象访问者方法是否保证有效,或者这种方法是否存在一些陷阱?
Java 中对于 this
指针给出了哪些保证?
I was dealing with hibernate, trying to figure out the run-time class behind proxied instances by using the visitor pattern. I then came up with an AbstractVisitable
approach, but I wonder if it will always produce correct results.
Consider the following code:
interface Visitable {
public void accept(Visitor v);
}
interface Visitor {
public void visit(Visitable visitorHost);
}
abstract class AbstractVisitable implements Visitable {
@Override
public void accept(Visitor v) {
v.visit(this);
}
}
class ConcreteVisitable extends AbstractVisitable {
public static void main(String[] args) {
final Visitable visitable = new ConcreteVisitable();
final Visitable proxyVisitable = (Visitable) Proxy.newProxyInstance(
Thread.currentThread().getContextClassLoader(),
new Class<?>[] { Visitable.class }, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method,
Object[] args) throws Throwable {
return method.invoke(visitable, args);
}
});
proxyVisitable.accept(new Visitor() {
@Override
public void visit(Visitable visitorHost) {
System.out.println(visitorHost.getClass());
}
});
}
}
This makes a ConcreteVisitable
which inherits the accept
method from AbstractVisitable
. In c++, I would consider this risky, since this
in AbstractVisitable could be referencing to AbstractVisitable::this
, and not ConcreteVisitable::this
. I was worried that the code under certain circumstances would print class AbstractVisible
. Yet the code above outputs class ConcreteVisitable
, even though I hid the real type behind a dynamic proxy (the most difficult case I could come up with). Is the abstract visitor approach above guaranteed to work, or are there some pitfalls with this approach?
What guarantees are given in Java with respect to the this
pointer?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
正如您可能猜到的那样,
this
始终指向此对象。您在层次结构中使用哪种类型是无关紧要的,除非您使用它来引用非虚拟事物(例如私有字段/方法,或者上帝禁止的静态方法)。getClass()
是虚拟的。现在我预计您可能会混淆
this
的行为,认为 Java 具有多重分派。事实并非如此。如果你将你的 Visitor 更改为这样:然后像这样实现它:
它确实会打印“Visitable”,而不是“ConcreteVisitable”,因为 Java 不执行 双重调度。
this
always points to this object, as you might guess. Which type in the hierarchy you use it from is irrelevant, unless you're using it to reference non-virtual things (like private fields/methods, or God forbid, static methods).getClass()
is virtual.Now I expect maybe you're confusing the behaviour of
this
for thinking Java has multiple dispatch. It doesn't. If you change your Visitor to this:And then implemented it like this:
It would indeed print "Visitable", not "ConcreteVisitable" since Java does not perform double dispatch.
您的动态代理将accept(...) 调用传递给底层的Visible,然后调用visit(...),并将其自身作为参数传递。除了传递accept()调用之外,代理从不参与任何事情,因此当它实现visit(...)方法时,所处理的Visible是代理的具体实例。
Your dynamic proxy passes the accept(...) call through to the underlying Visitable, which then calls visit(...), passing itself as the argument. The proxy is never involved in anything except passing through the accept() call, so by the time it gets to the implementation of the visit(...) method, the Visitable being dealt with is the concrete instance, shorn of the proxy.