1

我一直在努力升级我的 Java 代码基线,以便它遵循良好的安全实践并遇到与泛型相关的问题。假设您有以下内容:

public class SomeClass<T>
{
    private T value;
    public T getValue()
    {
        return value;
    }

    public void setValue(T value)
    {
        this.value = value;
    }
}

我还没有找到关于如何编辑这些方法的好答案,以便值不会像在这个示例类中那样泄漏,对于没有实现 Clonable 并且在某些情况下没有默认构造函数的通用对象。

4

4 回答 4

1

据我了解,您要确保外部没有任何东西SomeClass可以改变 object value

在 C++ 中,您可以返回一个 const 引用(完全避免复制),但 Java 没有。那么让我们看看复制...

首先,要知道有些对象是不能复制的。例如,流、gui 元素等。因此,尝试复制所有对象从一开始就是无望的尝试。

但是可复制的对象

在 Java 中,您不能调用泛型的复制构造函数(或任何其他构造函数)(调用泛型类型的构造函数)。

Cloneable接口,但这实际上只不过是一个clone有效的承诺;它实际上并不clone公开。因此,对于泛型,您必须使用反射,如此处所示

不幸的是,没有好的解决方案。唯一可行的(除了改变你的类的目的或语义)是使用clone上面链接中显示的方法,并意识到某些对象不能被复制。

最终,最好的办法是找到一个不需要这样做的解决方案。制作一个(非通用)只读包装类来公开非变异方法。或者在文档中规定不得调用变异方法。

于 2013-11-09T20:22:31.350 回答
0

我可以看到三种方法:

  1. 制作副本。这当然只适用于可以复制的类型(并且您知道如何复制)。

  2. 仅支持不可变类型。

  3. 删除getValue(). 相反,提供直接操作的方法this.value而不将其暴露在类之外。在这种方法中,setValue()仍然可能会出现问题(您需要确保调用者在调用后不会保留对象引用setValue())。

如果T可以是您无法控制的任意类型,则选项 1 和 2 将不适合。

于 2013-11-09T20:19:41.550 回答
0

我相信我不理解你......如果你想限制一个泛型类型,你应该使用泛型类型中不等于通用类的扩展关键字。如果你只使用类,实现 Clonable 是如何实例化这个类的。一个例子:

  public class Stack {


    public static void main(String[] args) {
        SomeClass<Animal> sc = new SomeClass<>(); //This generate an error because doesnt implements Clonable interface
        SomeClass<Person> sc1 = new SomeClass<>();
    }

}
class SomeClass<T extends Comparable> //Note that extends means implements or the common extends
{
    private T value;
    public T getValue()
    {
        return value;
    }

    public void setValue(T value)
    {
        this.value = value;
    }
}

class Person implements Comparable<Person>{
    @Override
    public int compareTo(Person p){
        return 0;
    }
}
class Animal {

}

我希望我能帮助你。:)

于 2013-11-09T20:24:43.253 回答
0

状态封装在可变对象中的对象通常不应向外界公开对该对象的任何引用,并且应避免向外界提供对声称封装其状态的任何可变对象(甚至是副本)的引用。问题是给定的代码:

Foo foo = myEntity1.getFoo();
foo.bar = 23;
myEntity2.setFoo(foo);
foo.bar = 47;
myEntity3.setFoo(foo);

没有明确的迹象表明更改是否或如何foo.bar影响各个实体。如果代码改为:

Foo foo = myEntity1.getFoo();
foo = foo.withBar(23); // makes a new instance which is like foo, but where bar==23
myEntity2.setFoo(foo);
foo = foo.withBar(47); // makes a new instance which is like foo, but where bar==47
myEntity3.setFoo(foo);

很明显's的bar属性不受影响,of的属性为23, of 的属性为47。如果是可变类,则模式应为:myEntity1foomyEntity2myEntity3foo

Foo foo = new Foo();
myEntity1.writeTo(foo); // Copy properties from myEntity1 to the supplied instance
foo.bar = 23;
myEntity2.readFrom(foo); // Copy properties from the supplied instance to myEntity2
foo.bar = 47;
myEntity2.readFrom(foo); // Copy properties from the supplied instance to myEntity3

在这里,myEntity1不是给调用者一个对象,而是将数据复制到调用者提供的对象中。因此,调用者不应期望写入foo.bar直接影响实体,而只是更改将在后续readFrom调用中写入的内容,这一点就更清楚了。

于 2013-11-13T20:06:06.050 回答