3

クラスのすべてのインスタンスで表示される定数をクラスに設定したいと思います。

まず、「静的」として宣言する必要があるかどうかわかりません。私が理解している限り、静的フィールドの変更(インスタンスの1つによって行われる)は他のインスタンスによって見られます(したがって、静的変数は特定のインスタンスにバインドされません)。さらに、静的フィールドはインスタンスを使用せずに変更できます(クラスを直接操作します)。したがって、静的フィールドのこれらすべての特別なプロパティは、それを変更する方法と、これらの変更の効果に関連しています。しかし、私の場合は定数が必要です(したがって、「変更」の問題はここでは関係ありません)。したがって、おそらく「静的」を使用する必要はありません。右?

次に、私のセットには多くの要素が含まれているので、セットの値を一度に定義したくありません(変数を作成するとき)。つまり、セットを宣言してから、このセットに要素を段階的に追加したいと思います。しかし、定数を使って作業する場合、それはできません。セットの値を指定して一定にすることはできますか?

第三に、メソッドの外部で変数の値を変更しようとすると、いくつかの問題が発生する可能性があることに気付きました。それで、それはどのように機能しますか?

追加した:

わかった。答えのおかげで、「final」と「static」である必要があることがわかりました(これは定数セットであり、特定のインスタンスに関連付けられないため、クラスのすべてのインスタンスに表示される必要があります)。しかし、私はまだ問題を抱えています。「追加」を使用してセットを指定したかったのですが、定数(最終)の場合はセットに追加できません。さらに、メソッドの外部で変数の値を変更することはできません(なぜですか?)。とにかく、私はセットを定義するために「追加」の使用法を主張しません。すぐに定義する準備ができています。しかし、私はそれを行う方法がわかりません。私はそのようなことを試みました:

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"}));

そして、彼らは機能しませんでした。

追加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);
    }
}


1.fillSetメソッドには「set」と呼ばれる1つの変数があります。なぜメソッドで使用されないのですか?
2.何がSomeType()入っていfillSetますか?この方法は何をしますか?
3.何をしfillSetますか?例の後半で、このメソッドに空のセットを指定します。何のために?
4.何のためにtempSet最終として宣言しますか?
5.正確には何をunmodifiableSetしますか?名前からすると、変更できないセットが生成されると思います。しかし、なぜ宣言するのに不十分なyourSetFieldfinalですか?それよりも一定だろう。

4

4 に答える 4

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);
    }
}

今は非公開なので、クラス外の誰もアクセスできません。また、変更不可であるため、誰もその内容を変更することはできません。

いつでも要素を追加したい場合は、同時実行性の問題があります-エクストラネオンの回答を読んでください。

編集
要求に応じて、このコードが何をするかを説明します。

最初の謎の <> ブラケット: Java 1.5 以降を使用していて、ジェネリックを使用していると仮定しました。簡単に言うと、リスト型の変数を宣言すると、オブジェクトが保持されます。その中に文字列を保持したい場合は、リストから文字列を取得するときにキャストする必要があります。例

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

String へのキャストが必要です。さらに、BigDecimal を myList に追加することを妨げるものは何もありません。しかし、それを取得して String にキャストしようとすると、ClassCastException が発生します。

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

そのため、Java 1.5 ではジェネリックが導入されています。リストに文字列のみを含めることができるように指定できます。構文では <> 括弧を使用します。

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

セットなどの他のコレクションにも同じことが当てはまります。リストから取得する方が便利なので、リストについて書きました。SomeTypeSet に何を保持したいのかわからなかったので、この例で使用しました。保存したいオブジェクトのタイプに置き換える必要があります。

今 - 静的ブロック。静的フィールドを初期化する方法は 2 つあります - 宣言で直接:

static private int instanceCount = 0;

これは、初期値が単純な式の場合に便利です。
または静的初期化ブロックで

static {
    // some code, that can use class static variables, class static methods, declare its own variables etc.
}

これは、一部の静的フィールドの初期値にさらに複雑な計算が必要な場合に便利です。

そして今、あなたの質問

  1. のパラメータsetfillSet使用されます。それに追加された要素があります:set.add(new SomeType());
  2. セットに何を保持したいのかわからなかったので、要素のタイプに名前を付けましたSomeType。使用したいタイプに交換してください。パラメーターなしのコンストラクターを呼び出すnew SomeType();(仮想の) のインスタンスを作成します。SomeType
  3. fillSetその名前が意味することを正確に行います-セットを取り、それを埋めます(それにいくつかの値を追加します)。それに空のセットを与えて、その結果、要素fillSetが入ったセットを取得します。fillSetセットを初期化するすべてのコードを配置する場所です。これは分けていただいて結構です。
  4. tempSet一度割り当てられ、再割り当てされることのない静的初期化ブロック内のローカル変数です。これを表現するために、私はそれを最終的に宣言します。これはfindBugsを使用して得た習慣であり、可読性に優れていると思います。
  5. yourSetField を final にするということは、yourSetField = new HashSet<SomeType>()一度初期化すると書き込みができないことを意味します。しかし、アクセスできる人は誰でもyourSetField書くことができますyourSetField.add(...)。が unmodifiableSet の場合yourSetField、それに追加すると実行時に例外が発生します ( UnsupportedOperationException)。言い換えれば、 final はyourSetField、別のオブジェクトを指すことができないことを意味します (そして、コンパイラはそれを保証します)。unmodifiableSet は、セットからオブジェクトを追加または削除できないことを意味します。コンパイルはできますが、実行時に壊れます。
于 2010-03-10T15:29:03.463 に答える
5

クラスでは、次のようなものが必要です。

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

}

ImmutableSetJonが示唆するように、私はグアバを使用するので、of( ... )メソッドまたはビルダーインターフェースを使用します(データのフィードがある場合-データをハードコーディングしている場合は、of()を使用するだけです)、どちらもAPI で十分にカバーされています。その他のオプションには、コレクションからの変更不可能な方法によるラッピングが含まれます。

于 2010-03-10T15:47:54.313 に答える
4

変更への対処方法ではなく、クラスの特定のインスタンスに固有ではないため、静的が必要ようです。

最終的な静的変数を用意し、タイプの静的初期化ブロックで通常のセットを作成してから、通常のセットから不変のセット(Guavaで提供されているものなど)を作成することをお勧めします。その不変のセット参照を静的最終変数に割り当てます。仕事は終わりました。

于 2010-03-10T15:05:02.600 に答える
2

私はあなたが何staticを意味するか知っていると思います。内容ではなくセットについて言及したように、「一定」です。つまり、インスタンスが別のセットをそこに配置することはできません。それを作成することをお勧めしますfinal

最終的な静的セットはすべてのインスタンスで同じであり、そのセットの内容はすべてのインスタンスで変更できます。

別の問題が発生します。並行性。クラスの複数のインスタンスが同時にセットを変更した場合はどうなりますか?セットは何をすべきですか?セットを同期セットでラップすることで、それをキャッチできます。

全体として、宣言は次のようになります。

private static final Set<YourElement> mySet = Collections.synchronizedSet(new HashSet());

Bozhoが示したように、事前に知っているコンテンツを静的ブロックに入力したり、実行時に他の要素を追加したりできます。

そのような宣言で次のようなステートメント

void myFoo() {
  mySet = new HashSet(); // will fail as it's final
}

想定どおりに失敗し、セットへの同時更新が機能します。

定数値のセットが必要な場合は、次のようにすることができます。

private static final Set<YourElement> mySet;
static {
   Set<YourElement> tmpSet = new HashSet();
   tmpSet.add(...);
   mySet = Collections.unmodifiableSet(tmpSet);
}

しかし、私は他の誰かが最初だったのを見ます:)

于 2010-03-10T15:18:37.283 に答える