1. Обзор
Ранее мы обсуждали основы дженериков Java . В этом уроке мы рассмотрим универсальные конструкторы в Java.
Универсальный конструктор-это конструктор, который имеет по крайней мере один параметр универсального типа.
Мы увидим, что универсальные конструкторы не обязательно должны находиться в универсальном классе, и не все конструкторы в универсальном классе должны быть универсальными.
2. Неродовой класс
Во-первых, у нас есть простой класс Запись , который не является универсальным классом:
public class Entry { private String data; private int rank; }
В этом классе мы добавим два конструктора: базовый конструктор с двумя параметрами и универсальный конструктор.
2.1. Базовый конструктор
Первый конструктор Entry – это простой конструктор с двумя параметрами:
public Entry(String data, int rank) { this.data = data; this.rank = rank; }
Теперь давайте используем этот базовый конструктор для создания объекта Entry :
@Test public void givenNonGenericConstructor_whenCreateNonGenericEntry_thenOK() { Entry entry = new Entry("sample", 1); assertEquals("sample", entry.getData()); assertEquals(1, entry.getRank()); }
2.2. Универсальный конструктор
Далее, наш второй конструктор является универсальным конструктором:
publicEntry(E element) { this.data = element.toString(); this.rank = element.getRank(); }
Хотя Вход класс не является универсальным, у него есть универсальный конструктор, так как у него есть параметр элемент типа E .
Универсальный тип E ограничен и должен реализовывать как Ранжируемые , так и Сериализуемые интерфейсы.
Теперь давайте посмотрим на интерфейс Rankable , который имеет один метод:
public interface Rankable { public int getRank(); }
И, предположим, у нас есть класс Product , который реализует интерфейс Runnable :
public class Product implements Rankable, Serializable { private String name; private double price; private int sales; public Product(String name, double price) { this.name = name; this.price = price; } @Override public int getRank() { return sales; } }
Затем мы можем использовать универсальный конструктор для создания Записи объектов с использованием Продукта :
@Test public void givenGenericConstructor_whenCreateNonGenericEntry_thenOK() { Product product = new Product("milk", 2.5); product.setSales(30); Entry entry = new Entry(product); assertEquals(product.toString(), entry.getData()); assertEquals(30, entry.getRank()); }
3. Общий класс
Далее мы рассмотрим универсальный класс под названием Generic Entry :
public class GenericEntry{ private T data; private int rank; }
Мы добавим те же два типа конструкторов, что и в предыдущем разделе в этом классе.
3.1. Базовый конструктор
Во-первых, давайте напишем простой, не универсальный конструктор для нашей Общей записи класса:
public GenericEntry(int rank) { this.rank = rank; }
Даже не смотря на Общая Запись это универсальный класс, это простой конструктор, который не имеет параметра универсального типа.
Теперь мы можем использовать этот конструктор для создания универсальной записи :
@Test public void givenNonGenericConstructor_whenCreateGenericEntry_thenOK() { GenericEntryentry = new GenericEntry (1); assertNull(entry.getData()); assertEquals(1, entry.getRank()); }
3.2. Универсальный конструктор
Далее, давайте добавим второй конструктор в наш класс:
public GenericEntry(T data, int rank) { this.data = data; this.rank = rank; }
Это универсальный конструктор, так как он имеет параметр data универсального типа T . Обратите внимание, что нам не нужно добавлять в объявление конструктора, так как оно неявно присутствует.
Теперь давайте протестируем наш универсальный конструктор:
@Test public void givenGenericConstructor_whenCreateGenericEntry_thenOK() { GenericEntryentry = new GenericEntry ("sample", 1); assertEquals("sample", entry.getData()); assertEquals(1, entry.getRank()); }
4. Универсальный конструктор с другим типом
В нашем универсальном классе мы также можем иметь конструктор с универсальным типом, который отличается от универсального типа класса:
publicGenericEntry(E element) { this.data = (T) element; this.rank = element.getRank(); }
Эта Общая запись конструктор имеет параметр элемент с типом E , который отличается от типа T . Давайте посмотрим на это в действии:
@Test public void givenGenericConstructorWithDifferentType_whenCreateGenericEntry_thenOK() { Product product = new Product("milk", 2.5); product.setSales(30); GenericEntryentry = new GenericEntry (product); assertEquals(product, entry.getData()); assertEquals(30, entry.getRank()); }
Обратите внимание, что:
- В нашем примере мы использовали Product ( E ) для создания Общей записи типа Сериализуемой ( T )
- Мы можем использовать этот конструктор только тогда, когда параметр типа E может быть приведен к
5. Несколько Универсальных Типов
Далее, у нас есть универсальный класс Запись карты с двумя универсальными типами:
public class MapEntry{ private K key; private V value; public MapEntry(K key, V value) { this.key = key; this.value = value; } }
Запись карты имеет один универсальный конструктор с двумя параметрами, каждый из которых имеет другой тип. Давайте использовать его в простом модульном тесте:
@Test public void givenGenericConstructor_whenCreateGenericEntryWithTwoTypes_thenOK() { MapEntryentry = new MapEntry ("sample", 1); assertEquals("sample", entry.getKey()); assertEquals(1, entry.getValue().intValue()); }
6. Подстановочные знаки
Наконец, мы можем использовать подстановочные знаки в универсальном конструкторе:
public GenericEntry(Optional extends Rankable> optional) { if (optional.isPresent()) { this.data = (T) optional.get(); this.rank = optional.get().getRank(); } }
Здесь мы использовали подстановочные знаки в этой общей записи конструкторе для привязки Необязательного типа:
@Test public void givenGenericConstructorWithWildCard_whenCreateGenericEntry_thenOK() { Product product = new Product("milk", 2.5); product.setSales(30); Optionaloptional = Optional.of(product); GenericEntry entry = new GenericEntry (optional); assertEquals(product, entry.getData()); assertEquals(30, entry.getRank()); }
Обратите внимание, что мы должны иметь возможность привести необязательный тип параметра (в вашем случае Product ) к типу Generic Entry (в вашем случае Сериализуемый ).
7. Заключение
В этой статье мы узнали, как определять и использовать универсальные конструкторы как в универсальных, так и в не-универсальных классах.
Полный исходный код можно найти на GitHub .