2

在我的 Java 大学课程中,我了解了隐私泄露的概念,其中公共 getter 返回对私有可变对象的引用。

他们给出的示例如下:(如果语法不太正确,请原谅我,我正在记忆中工作)

private HashSet<*> priv = new HashSet<*>

public Collection<*> getPriv () {
    return this.priv;
}

现在的问题是对象的客户端现在有机会故意或以其他方式破坏私有 HashSet。

在课程中,建议的解决方案是使用以下内容:

public Collection<*> getPriv () {
    return Collections.unmodifiableCollection (this.priv);
}

这对我来说似乎是一个很好的解决方案,因为不仅对象的内部状态不受外部修改的影响,任何修改返回的 unmodifiableCollection 的尝试都会触发异常。但是,问题在于它仅适用于集合。似乎没有其他可变 Java 类的等价物。

从那以后,我读过的大多数 Java 书籍都建议以下内容:

public Collection<*> getPriv () {
    return this.priv.clone ();
}

这适用于任何可克隆对象,但返回的对象可以修改为客户端对象的内容。对象的内部状态仍然受到保护,但现在如果我尝试修改无法真正修改的数据,我不会得到异常。这意味着我可能会在获取私有集合并对其进行修改时出错,并且对为什么我的更改没有反映在对象中感到困惑,因此我将一类错误(修改私有状态)换成了另一类(修改应该是不可变的克隆)。

是否有一种更通用的方法return Collections.unmodifiableCollection (this.priv);可以与任何类(或至少任何满足某些先决条件的类,例如实现可克隆)一起使用,或者是我唯一的选择来实现我可能想要的所有私有类的可变和不可变版本通过吸气剂公开?

4

1 回答 1

3

恐怕答案是肯定的。

请注意, Collections.unmodifiableCollection 仅返回一个视图。本质上,Collections 包含一个适配器类,它接收任何Collection并将某些方法调用转发给它。对于“危险”方法,它会引发异常。当然,这依赖于传入的底层集合以理智的方式实现事物。如果getSize()改变了对象,那么getSize()对适配器的调用仍会将其转发给基础类,然后对其进行修改。

您可以通过限制返回给客户端的不同类(或接口)的数量来减少工作量。您还可以默认使更多类不可变,这是函数式语言中的一种常见范例,它使事情变得更加简单。不幸的是,Java 使处理不可变对象变得不必要地难看。

还有一些可能性,比如自动生成不可变视图,但这很复杂,并且需要您有一种方法来决定无论如何要转发哪些方法。

最后,这些都不能保护您免受setAccessible或类似的伤害。但在这种情况下,他们故意违反标准 VM 约束,所以这不是你真正应该担心的事情。如果您担心安全性,无论如何您都需要在 SecurityManager 中运行所有不受信任的代码。

于 2013-04-17T22:57:39.573 回答