Set
- это интерфейс, который реализует HashSet
, поэтому, если вы сделаете это:
Set<E> mySet = new HashSet<E>();
Вы по-прежнему будете иметь доступ к функциональности HashSet
, но у вас также есть возможность заменить в будущем конкретный экземпляр на другой класс Set
, такой как LinkedHashSet
или TreeSet
, или другая реализация.
В первом методе используется конкретный класс, позволяющий заменить класс экземпляром самого себя или подклассом, но с меньшей гибкостью. Например, TreeSet
не может использоваться, если тип вашей переменной HashSet
.
Это пункт 52 из книги Джошуа Блоха Effective Java, 2nd Edition .
Обращайтесь к объектам по их интерфейсам
... Вы должны отдавать предпочтение использованию интерфейсов, а не классов для ссылки на объекты. Если существуют соответствующие типы интерфейса, тогда все параметры, возвращаемые значения, переменные и поля должны быть объявлены с использованием типов интерфейса. Единственный раз, когда вам действительно нужно обратиться к классу объекта, это когда вы создаете его с помощью конструктор ...
// Обычно хорошо - использует интерфейс как тип
List<T> tlist = new Vector<T>();
// Типично Плохо - в качестве типа используется конкретный класс!
Vector<T> vec = new Vector<T>();
Эта практика имеет некоторые предостережения - если требуемая реализация имеет особое поведение, не гарантированное универсальным интерфейсом, то вы должны соответствующим образом задокументировать свои требования.
Например, Vector<T>
- это synchronized
, тогда как ArrayList<T>
(также реализатор List<T>
) - нет, поэтому, если вам нужны синхронизированные контейнеры в вашем проекте (или нет), вам необходимо документировать это .