Как работает java.util.EnumSet <E>?

Класс EnumSet<E> определяется как:

public abstract class EnumSet<E extends Enum<E>>
extends AbstractSet<E>
implements Cloneable, Serializable

в JCF. Кроме того, большинство методов, которые реализует сам класс, являются статическими. Наконец, класс не реализует методы add(), iterator(), remove(), size(), contains() или isEmpty() и просто наследует их от AbstractSet, который не реализует их. У меня есть два вопроса:

  • Как точно создаются объекты EnumSet?
  • Почему я могу использовать метод add() для объектов EnumSet?

Ответ 1

Большинство статических методов, которые вы видите, это методы factory (of(), complementOf(), allOf() и т.д.).

Эти методы возвращают экземпляр EnumSet. Фактический тип EnumSet, созданный и возвращаемый этими методами, является подклассом EnumSet (RegularEnumSet, JumboEnumSet), которые не являются частью общедоступного API, но реализуют все необходимые методы. Все, что вам нужно знать, это то, что они реализуют EnumSet.

Ответ 2

EnumSet является абстрактным классом, поэтому ему не нужно реализовывать какие-либо абстрактные методы, которые он наследует. Он передает эту ответственность за свои не абстрактные подклассы.

Вы можете вызвать нереализованные методы, потому что вы на самом деле вызываете их в экземпляре подкласса EnumSet. (Поскольку EnumSet является абстрактным, он не может быть непосредственно создан сам.)

Ответ 3

import java.util.*;
enum Foo {
  A, B
}
class a {
  public static void main(String[] args) {
    System.out.println(EnumSet.noneOf(Foo.class));
    System.out.println(EnumSet.of(Foo.A));
    System.out.println(EnumSet.of(Foo.A).getClass());
  }
}

Отпечатки:

[]
[A]
class java.util.RegularEnumSet 

Что касается реализации, эта ссылка содержит описание:

EnumSet является абстрактным классом и обеспечивает два конкретных реализаций, java.util.RegularEnumSet и java.util.JumboEnumSet. Основное различие между RegularEnumSet и JumboEnumSet заключается в том, что бывший использует переменную long для хранения элементов, а затем использует long[] для сохраните его элемент. Поскольку RegularEnumSet использует переменную long, которая является 64-битный тип данных, он может удерживать только большую часть элемента. Вот почему когда пустой EnumSet создается с использованием метода EnumSet.noneOf(), он выберите RegularEnumSet, если ключевой юниверс (количество экземпляров enum в Key Enum) меньше или равно 64 и JumboEnumSet, если ключевой юниверс более 64.

Это означает, что EnumSet выберет для вас правильную реализацию.

Ответ 4

  • Как точно создаются объекты EnumSet?

EnumSet является "абстрактным классом" и предпочтительнее, чем HashSet, когда у вас есть несколько "ключей", которые известны заранее. Например, если у вас есть ключи конфигурации.

производительность лучше, чем HashSet, потому что "... поскольку константы Enum уникальны и имеют заданную длину, так как вы не можете определить новую константу enum в runtime, он позволяет дизайнеру Java API оптимизировать EnumSet..." (Подробнее: http://javarevisited.blogspot.com/2014/03/how-to-use-enumset-in-java-with-example.html#ixzz3jNcyB8ve)

Вы можете создать экземпляр с помощью большого количества методов factory, например EnumSet.of(...)

  1. Почему я могу использовать метод add() для объектов EnumSet?

После того, как вы создали объект EnumSet, вы можете добавить во время выполнения другой элемент с помощью метода "добавить". Если у вас есть, например, список ключей конфигурации, вы можете представить EnumSet "выбранные" ключи и добавить их во время выполнения.

package sample.test;
import java.util.EnumSet;

public class Foo {

  public enum SimpleConfigEnum { KEY1, KEY2, KEY3};

/**
 * Example of EnumSet with add
 */
public static void main(String[] args) {

    //Create an enumSet with two elements: KEY1,KEY2
    EnumSet<SimpleConfigEnum> eSet = EnumSet.of(SimpleConfigEnum.KEY1, SimpleConfigEnum.KEY2);
    System.out.println(eSet);

    //... add another element --> KEY3
    eSet.add(SimpleConfigEnum.KEY3);
    System.out.println(eSet);
  }

 }

Вывод:

[KEY1, KEY2]
[KEY1, KEY2, KEY3]