Java:防止对象引用在方法外部使用
我定义了一个接口Java:防止对象引用在方法外部使用,java,Java,我定义了一个接口RecordVisitor,声明如下: public interface RecordVisitor<K, V, Result> { public Result visit(Record<K, V> rec); } 公共接口记录访问者{ 公众结果访问(记录rec); } 其思想是,visit的实现将被一个记录对象调用,执行它们的逻辑,并返回一个结果。我希望防止实现隐藏rec值,并在visit调用之外使用它 我认为实现这一点的唯一方法是将状态添加
RecordVisitor
,声明如下:
public interface RecordVisitor<K, V, Result> {
public Result visit(Record<K, V> rec);
}
公共接口记录访问者{
公众结果访问(记录rec);
}
其思想是,visit
的实现将被一个记录对象调用,执行它们的逻辑,并返回一个结果。我希望防止实现隐藏rec
值,并在visit
调用之外使用它
我认为实现这一点的唯一方法是将状态添加到Record
,如果在Record对象不“活动”时调用了任何方法,则抛出IllegalStateException
。然后,我会将可怕的警告写入javadoc,并希望实现者阅读它
是否有更可靠的方法防止使用
记录
对象在访问
方法之外使用?如果可能的话,我想构建一个接口,如果违反约定,它会导致编译时错误。没有办法阻止实现者将对对象的引用存储为其访问实现的一部分
然而,这里有一个更大的哲学问题。如果您不信任实现RecordVisitor
接口的代码,那么为什么要使用该代码?如果您这样做了,那么如果代码保留对对象的引用,为什么会出现问题呢
我认为实现这一点的唯一方法是向记录添加状态,如果在记录对象上调用了任何方法,而该方法不是“活动”的,则抛出IllegalStateException
如果您不信任实现RecordVisitor
接口的程序员,这仍然是不够的。没有什么可以阻止实现者创建新方法
public void foo() {
this.rec.activate();
// Do something, and there is no IllegalStateException
this.rec.deactivate();
}
要记录的将显示为从内部调用访问
,但实际上不是从内部调用访问
首先,牢记@AdamMihalcin的建议
现在,如果您仍然希望控制对记录
对象的访问,请查看Java的代理
类及其关联的调用处理程序
。这允许您创建具有记录接口的代理对象(假设记录是一个接口)。然后,附加到代理的InvocationHandler
会将对接口上方法的所有调用转发给realRecord
对象。当对访问者的调用返回时,您可以调用InvocationHandler
上的invalidate()
等方法,指示它停止向真实记录对象转发调用
下面是一个调用处理程序的示例
package test.proxy ;
import java.lang.reflect.InvocationHandler ;
import java.lang.reflect.Method ;
import java.lang.reflect.Proxy ;
public class CancelableObjectInvocationHandler
implements InvocationHandler
{
private Object _realObject ;
public CancelableObjectInvocationHandler ( Object realObject )
{
_realObject = realObject ;
}
public Object invoke ( Object proxy, Method method, Object[] args )
throws Throwable
{
Object ret = null ;
if ( method.getName ( ).equals ( "equals" ) )
{
// If we are invoking the equals method, we have to compare the
// Invocation Handlers since the Proxies forward the method call
boolean isEquals = true ;
if ( isEquals )
{
isEquals = ( args[0] instanceof Proxy ) ;
}
if ( isEquals )
{
Proxy otherProxy = (Proxy) args[0] ;
isEquals = this.equals ( Proxy.getInvocationHandler ( otherProxy ) ) ;
}
return new Boolean ( isEquals ) ;
}
else if ( null != _realObject )
{
// The object is active, so execute the method call.
ret = method.invoke ( _realObject, args ) ;
}
else
{
throw new IllegalStateException (
"Attempt to access an invalidated Object" ) ;
}
return ret ;
}
public Object getRealObject ( )
{
return _realObject ;
}
protected void invalidate ( )
{
_realObject = null ;
}
}
你能使记录不可变吗?若并没有,那个么制作一个防御性的拷贝怎么样?你们能不能避免给记录任何公开的方法来改变它?这似乎是最简单、最面向对象的方法。如果有人调用您的函数并必须向其中传递记录,您对他们控制的对象无能为力。我认为在这种情况下,getRealObject
不是一个好主意。;-)实际上,它不应该有太大的区别,因为传入的代理对象只响应它所代理的接口中的方法。但是您是对的,在这种情况下,可能没有什么理由使用getRealObject()
方法。:-)恶意用户可以通过调用Proxy.getInvocationHandler
获取调用处理程序,然后调用方法getRealObject
,以获取引用。这在这个用例中有很大的不同。@a.H.同意。在最初使用它的设置中,这不是一个大问题。幸运的是,Record
是一个接口,实现是一个私有嵌套类。激活/停用方法将在此处声明,任何RecordVisitor
s都无法触及。我有点想这就是答案。