Другие ответы уже ответили, каковы конкретные подклассы EnumSet
, которые фактически реализуют абстрактный класс EnumSet
. Я попытаюсь прояснить, как мы можем получить экземпляр абстрактного типа EnumSet
, если мы не подклассифицировали его.
Обратите внимание, что EnumSet
не имеет конструктора, поэтому он не предназначен для использования как обычный класс:
EnumSet set = new EnumSet(...); // not like this
Скорее, чтобы создать EnumSet
, мы используем один из его статических инициализаторов (например, of
). Эти инициализаторы внутренне создадут объект типа JumboEnumSet
(если число констант enum велико) или RegularEnumSet
(в противном случае) и вернут ссылку на этот объект.
Поскольку JumboEnumSet
и RegularEnumSet
оба являются подклассами EnumSet
, их можно назначить переменной типа EnumSet
(это известно как расширяющее эталонное преобразование ).
Прелесть этого в том, что когда мы используем переменную типа EnumSet
, нам не нужно знать, какую конкретную реализацию мы используем. Фактически, оба JumboEnumSet
и RegularEnumSet
являются частным классом в пакете java.util
, поэтому мы не можем даже создать его напрямую.
Вы можете узнать больше о том, как EnumSet
реализовано внутри через его источник (см., Например, здесь для версии Java 9 ).
Другим примером обычно используемого типа в Java, который на самом деле не является конкретным классом, является Stream
. Stream
на самом деле интерфейс.