Java枚举类型是否需要进行防御性拷贝?

6

对于私有引用类型,应该返回所谓的“防御性副本”,以避免返回私有字段的引用。

我想知道对于私有枚举类型是否需要这样做。我在某个地方读到枚举是不可变引用类型,因此答案应该是“不需要”。这正确吗?


3
是的,答案是“不”。 - Konstantin Yovkov
1
@kocko:不,它们并不一定是不可变的。这取决于实现。 - Jon Skeet
1个回答

14

枚举本质上并不是不可变的,但您无法创建防御性副本,因为只有一组固定实例可用 - 您必须返回对现有实例之一的引用,而不是创建新实例。

通常情况下,枚举应该是不可变的,但为了抵消它们本质上不可变的说法:

enum BadEnum {
    INSTANCE;

    private int foo;

    private int getFoo() {
        return foo;
    }

    public int setFoo(int foo) {
        this.foo = foo;
    }
}

class Test {
    public static void main(String[] args) {
        BadEnum.INSTANCE.setFoo(10);
        System.out.println(BadEnum.INSTANCE.getFoo()); // Prints 10
    }
}

简而言之:

  • 使你的枚举不可变。我甚至不记得曾经想过要创建可变的枚举。
  • 你不应该尝试制作防御性拷贝。

2
嗯,带有可变字段的枚举类型...当我成为超级恶棍时,我会用这些代码让我的手下们维护代码而受苦...但在那之前,我必须多练习邪恶的笑声,回到现实世界... - ppeterka
你能推荐一些资源来确保枚举是不可变的吗?我原以为这与设计不可变类的模式相同,但我不确定并且找不到太多资料。 - NathanChristie
@NathanChristie:是的,没错。将所有变量都声明为final,并确保它们本身是不可变类型(例如Stringint,但不包括DateCalendar)。如果您必须使用可变类型,请确保永远不要直接返回引用 - 只需创建一个防御性副本即可。 - Jon Skeet

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接