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
会将对接口上方法的所有调用转发给real
Record
对象。当对访问者的调用返回时,您可以调用
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都无法触及。我有点想这就是答案。