2010-03-10 2 views
3

Я хотел бы иметь постоянный набор в моем классе, который будет виден для всех экземпляров класса.Как объявить постоянный набор, видимый для каждого экземпляра класса?

Во-первых, я не знаю, нужно ли объявлять его как «статический». Насколько я понимаю, любые изменения статического поля (сделанные одним из экземпляров) будут рассматриваться другими экземплярами (поэтому статическая переменная не привязана к конкретному экземпляру). Более того, статическое поле может быть изменено без использования какого-либо экземпляра (мы работаем непосредственно с классом). Таким образом, все эти специальные свойства статического поля связаны с тем, как его можно изменить и каковы последствия этих изменений. Но в моем случае я хотел бы иметь константу (поэтому проблемы с «изменениями» здесь не актуальны). Поэтому, вероятно, мне не нужно использовать «статический». Правильно?

Во-вторых, мой набор будет содержать много элементов, и я не хочу сразу определять значение набора (когда я создаю переменную). Другими словами, я хотел бы объявить набор, а затем добавлять элементы к этому набору шаг за шагом. Но я не могу этого сделать, если я работаю с константами. Возможно ли заданное значение набора, а затем сделать его постоянным?

В-третьих, я понял, что могут возникнуть проблемы, если я попытаюсь изменить значение переменных вне любого метода. Итак, как это работает?

ДОБАВЛЕНО:

OK. Благодаря ответу я понял, что он должен быть «final» и «static» (поскольку он является постоянным, и он не будет связан с каким-либо конкретным экземпляром, он должен быть видимым для всех экземпляров класса). Однако у меня все еще есть проблема. Я хотел указать набор, используя «add», и я не могу добавить в набор, если он является постоянным (final). Более того, я не могу изменить значения переменных вне методов (почему?). Во всяком случае, я не настаиваю на использовании «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"})); 

И они не работали.

ДОБАВЛЕНО 2:

Может кто-нибудь объяснить мне, мольбы, код дал Тадеуш 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 имеет одну переменную называется "установить". Почему он не используется в методе?
2. Что такое SomeType() в fillSet? Что делает этот метод?
3. Что делает fillSet? Позже в этом примере мы даем пустой набор этому методу. Зачем?
4. Зачем мы объявляем tempSet в качестве окончательного?
5. Что именно unmodifiableSet делать? Я думаю, по имени он генерирует набор, который не может быть изменен. Но почему этого недостаточно, чтобы объявить yourSetField как final? Чем это было бы постоянно.

+0

Когда вы говорите «set», вы имеете в виду java.util.Set ? –

+0

«Я не хочу сразу определять значение набора». Что это значит? что вы хотите добавить в набор в будущем? – Bozho

+0

@dbingham, Да. – Roman

ответ

4

Звучит так, как будто вы do хотите стать статичным, а не из-за того, как изменяются изменения, а потому, что это не относится ни к одному экземпляру вашего класса.

Я предлагаю вам иметь конечную статическую переменную, а в статическом блоке инициализации для вашего типа вы создаете регулярный набор, а затем создаете неизменяемый набор (например,the one предоставлен в Guava) от обычного. Назначьте неизменяемую ссылку на статическую конечную переменную. Работа выполнена.

+1

Поскольку это Java, я предполагаю, что вы имеете в виду статический блок инициализатора? – SteveD

+0

@stevendick: Да, исправится. –

2

Я думаю, вы знаете, что означает static. Поскольку вы упомянули Set, но не содержимое, является «константой», то есть ни один экземпляр не может помещать другой Set там, вы бы сделали это, чтобы сделать его final.

Окончательный статический набор одинаковый для всех экземпляров, а содержимое этого набора может быть изменено всеми экземплярами.

Возникает другая проблема; параллелизм. Что, если несколько экземпляров вашего класса m, одарить Set одновременно? Что должен сделать Set? Вы можете поймать это, обернув свой набор в Synchronized Set.

В общем, я думаю, что это заявление должно выглядеть следующим образом:

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

Но я вижу, кто-то был первым :)

+0

На самом деле, я хочу иметь постоянный набор. Таким образом, у меня не будет ситуации, когда несколько экземпляров пытаются изменить набор одновременно. Я хотел определить набор, используя «add», и это было проблемой (потому что я не могу добавить к постоянному набору, и я не могу изменять переменную вне методов). На данный момент я не настаиваю на этом решении (используя add). Это нормально, если я определяю набор сразу. Но я до сих пор не знаю, как это сделать. 'final static Set nameOfSet = new HashSet (" aaa "," bbb ")' не работает. – Roman

+0

Я также не понимаю разницы между «постоянным набором» и «постоянным содержимым набора». Для меня это одно и то же. Я думаю, что набор является постоянным, если его значение (т. Е. Контент) является постоянным. – Roman

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

Теперь - это частная, так что ни один за пределами вашего класса не может получить к нему доступ. И его неизменяемость, поэтому никто не может изменить свое содержание.

Если вы хотите добавить элементы в любое время, у вас есть проблема параллелизма - прочитайте ответ extraneon.

EDIT
По просьбе объясните, что делает этот код.

Первое - таинственные <> скобки: Я предположил, что вы используете Java 1.5 или выше и используется generics. В нескольких словах - если вы объявляете переменную типа List, она содержит объекты. Если вы хотите сохранить в нем строки, вы должны их отбросить, когда вы извлечете их из своего списка. Пример

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

Требуется приведение в строчку. Более того, ничто не мешает вам добавлять 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 может содержать только строки.Синтаксис использует <> скобки:

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 

То же относится и к другим коллекциям, как наборы. Я писал о списках, потому что извлечение из списков более удобно. Я использовал SomeType в моем примере, потому что я не знал, что вы хотите сохранить в своем наборе. Вы должны заменить его на тип объектов, которые вы хотите сохранить.

Теперь - статические блоки. Есть два способа инициализации статических полей - непосредственно в своем заявлении:

static private int instanceCount = 0; 

Это полезно, если начальное значение простое выражение.
Или в статическом блоке инициализации

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

Это полезно, если начальное значение для некоторых статических полей нуждается в более сложных вычислений.

А теперь ваши вопросы

  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.add(...). Если yourSetField является unmodifiableSet, добавление к нему приведет к исключению во время выполнения (UnsupportedOperationException). Другими словами: final означает, что вы не можете сделать yourSetField точкой другого объекта (и компилятор его гарантирует). unmodifiableSet означает, что вы не можете добавлять или удалять объекты из набора. Он будет компилироваться, но будет прерываться во время выполнения.
+0

Я не понимаю, что означает 'static {...}'. Я всегда думал, что это всего лишь модификатор полей и методов. Но, видимо, это не так. Я также не понимаю этот материал '<>'. Мне действительно нужно поставить эти скобки там? Или они просто указывают, что это что-то необязательное? Я могу заменить SomeType или ? – Roman

+0

ОК. Я получил материал «статического блока». '<>' все еще находится под вопросом. – Roman

+0

<...> являются частью спецификации Generics. В Википедии есть хорошая статья: http://en.wikipedia.org/wiki/Generics_in_Java – seanhodges

3

В своем классе вы хотите что-то вроде:

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

} 

Я бы с гуавы ImmutableSet, как говорит Джон, так как вы будете использовать метод of(...) или интерфейс строитель (если у вас есть некоторые тип подачи данных - если вы жестко кодируете данные, просто используйте()), оба из которых довольно хорошо описаны в API. Другие варианты включают обертывание через немодифицируемый метод из Коллекций.

Смежные вопросы