我应该如何为类的每个实例声明一个常量集?

Rom*_*man 3 java oop static final set

我希望在我的班级中有一个常量集,这对于班级的所有实例都是可见的.

首先,我不知道是否需要将其声明为"静态".据我所知,其他实例将看到静态字段的任何更改(由其中一个实例完成)(因此静态变量未绑定到特定实例).而且,静态字段可以在不使用任何实例的情况下进行更改(我们直接使用该类).因此,静态字段的所有这些特殊属性都与它的更改方式以及这些更改的影响有关.但在我的情况下,我希望有一个常数(所以"变化"问题在这里不相关).所以,我可能不需要使用"静态".对?

其次,我的集合将包含很多元素,我不想一次定义集合的值(当我创建变量时).换句话说,我想声明一个集合,然后逐步向该集合添加元素.但是,如果我使用常量,我就无法做到.是否可以指定集合的​​值,然后使其保持不变?

第三,我已经意识到,如果我尝试在任何方法之外更改变量的值,可能会出现一些问题.那么它是怎样工作的?

添加:

好.由于答案,我理解它应该是"final"和"static"(因为它是一个常量集,并且它不会与任何特定实例相关联,它应该对该类的所有实例都可见).但是我还是有问题.我想使用"add"来指定集合,如果它是常量(最终),我就无法添加到集合中.而且,我无法改变方法之外的变量值(为什么?).无论如何,我并不坚持使用"添加"来定义集合.我准备立即定义它.但我不知道该怎么做.我尝试过这样的事情:

final static Set allowedParameters = new HashSet("aaa","bbb");
final static Set allowedParameters = new HashSet(["aaa","bbb"]);
final static Set allowedParameters = new HashSet({"aaa","bbb"});
final static Set allowedParameters = new HashSet(Arrays.asList({"userName"}));
Run Code Online (Sandbox Code Playgroud)

他们没有工作.

增加2:

任何人都可以解释一下,请求Tadeusz Kopec提供的代码吗?

class YourClass {
    private static void fillSet(Set<SomeType> set) {
        // here you add elements, like
        set.add(new SomeType());
    }
    private final static Set<SomeType> yourSetField;
    static {
        final Set<SomeType> tempSet = new HashSet<SomeType>();
        fillSet(tempSet);
        yourSetField = Collection.unmodifiableSet(tempSet);
    }
}
Run Code Online (Sandbox Code Playgroud)


这个fillSet方法有一个叫做"set"的变量.为什么不在方法中使用?
2.什么SomeType()在fillSet?这种方法有什么作用?
3.做fillSet什么?稍后在示例中,我们为此方法提供一个空集.做什么的?
4.我们宣布什么tempSet是最终的?
究竟是unmodifiableSet做什么的?根据名称,它生成了一个无法修改的集合,我想.但是,为什么会是不够的申报yourSetField为final?比它也不变.

Tad*_*pec 6

是否要将元素添加到集合中,然后只读取其内容,或者您​​是否希望能够随时向其中添加元素?如果您创建一次,请执行以下操作:

class YourClass {
    private static void fillSet(Set<SomeType> set) {
        // here you add elements, like
        set.add(new SomeType());
    }
    private final static Set<SomeType> yourSetField;
    static {
        final Set<SomeType> tempSet = new HashSet<SomeType>();
        fillSet(tempSet);
        yourSetField = Collections.unmodifiableSet(tempSet);
    }
}
Run Code Online (Sandbox Code Playgroud)

现在 - 它是私人的,所以你班外的人都无法访问它.而且它不可修改,所以没有人可以改变它的内容.

如果你想随时添加元素,你会遇到并发问题 - 阅读extraneon的答案.

编辑
根据要求,我解释了这段代码的作用.

首先 - 神秘的<>括号: 我假设您使用的是Java 1.5或更高版本并使用了泛型.简而言之 - 如果您声明一个List类型的变量,它将保存对象.如果您希望将字符串保留在其中,则必须在从列表中检索字符串时将其强制转换.例

List myList = new ArrayList();
myList.add("Hello, my Jon Skeet Number decreases");
String firstElement = (String) myList.get(0);
Run Code Online (Sandbox Code Playgroud)

需要转换为String.此外,没有什么可以阻止您将BigDecimal添加到myList.但是如果你检索它并尝试强制转换为String,则会得到ClassCastException.

myList.add(0, BigDecimal.ZERO); // perfectly legal
String anotherString = (String) myList.get(0); // compiles, but ClassCastException at runtime
Run Code Online (Sandbox Code Playgroud)

所以Java 1.5引入了泛型.您可以指定,List只能包含字符串.语法使用<>括号:

List<String> myList = new ArrayList<String>();
myList.add("Hi everybody");
String firstElem = myList.get(0); // no cast required
myList.add(BigDecimal.ZERO); // compiler error: cannot cast BigDecimal to String
Run Code Online (Sandbox Code Playgroud)

同样适用于其他集合,例如集合.我写了关于列表的内容,因为从列表中检索更方便.我SomeType在我的例子中使用过,因为我不知道你想要保留在你的Set中.您应该将其替换为您要存储的对象类型.

现在 - 静态块.初始化静态字段有两种方法 - 直接在它们的声明中:

static private int instanceCount = 0;
Run Code Online (Sandbox Code Playgroud)

如果初始值是简单表达式,这将非常有用.
或者在静态初始化块中

static {
    // some code, that can use class static variables, class static methods, declare its own variables etc.
}
Run Code Online (Sandbox Code Playgroud)

如果某些静态字段的初始值需要一些更复杂的计算,这很有用.

现在你的问题

  1. 参数set的fillSet使用.添加了一个元素:set.add(new SomeType());
  2. 由于我不知道你想要保留在你的集合中,我命名了它的元素类型SomeType.它将替换为您要使用的类型.new SomeType();创建一个(假设的)实例来SomeType调用它的无参数构造函数.
  3. fillSet确切地说它的名字意味着什么 - 取一套并填充它(为它添加一些值).我们给它一个空集,以便我们得到一个带有元素的集合fillSet.fillSet是一个你应该把所有代码初始化你的集合的地方.把它分开是件好事.
  4. tempSet是静态初始化块中的局部变量,它被分配一次并且从不重新分配.为了表达这一点,我宣布它是最终的.这是我使用findBugs的习惯,我认为它对可读性有好处.
  5. 使yourSetField成为最终意味着yourSetField = new HashSet<SomeType>()一旦初始化你就无法编写.但任何可以访问的人都yourSetField可以写yourSetField.add(...).如果yourSetField是不可修改的Set,添加它将在runtime(UnsupportedOperationException)中导致异常.换句话说:final意味着你无法yourSetField指向另一个对象(并且编译器保证它).unmodifiableSet表示您无法在集合中添加或删除对象.它将编译但会在运行时中断.


Car*_*arl 5

在你的课堂上,你想要这样的东西:

private static final Set<Foo> mySet;
static {
 // ...initialize contents here.  guava example looks like:
mySet = ImmutableSet.of( adc, 123, etc );

}
Run Code Online (Sandbox Code Playgroud)

我会ImmutableSet按照 Jon 的建议使用 Guava ,因此您将使用该of( ... )方法或构建器界面(如果您有某种数据提要 - 如果您对数据进行硬编码,只需使用 of()),两者API 中已经很好地涵盖了。其他选项包括通过集合中的不可修改方法进行包装。