logo

Создание экземпляра обобщенного класса в Java: обход ограничений

Быстрый ответ

Чтобы создать экземпляр обобщённого класса в Java, нужно указать конкретные типы в угловых скобках:

Java
Скопировать код
ClassName<ConcreteType> obj = new ClassName<>();

Если предусмотрено несколько типов:

Java
Скопировать код
ClassName<Type1, Type2> obj = new ClassName<>();

Чтобы компилятор сам определил типы, используйте алмазный оператор <>. Для примитивных типов применяются обёрточные классы, например:

Java
Скопировать код
MyClass<Integer> myObj = new MyClass<>();

Встречаются и более сложные ситуации, такие как стирание типов или создание экземпляра типа T внутри класса. Давайте рассмотрим, как эти проблемы можно решить.

За рамками базовых знаний: продвинутое создание экземпляров

1. Ссылки на класс: решение проблемы стирания типов

Воспользуйтесь ссылкой на Class<T> при создании конструктора обобщённого класса. Это поможет создавать экземпляры динамически, что подводит нас к решению проблемы стирания типов.

Java
Скопировать код
public class Foo<T> {
    private Class<T> type;

    public Foo(Class<T> type) {
        this.type = type;
    }

    public T createInstance() throws IllegalAccessException, InstantiationException {
        return type.newInstance();
    }
}

2. Фабрики: создание объектов по шаблону

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

Java
Скопировать код
public interface Factory<T> {
    T create();
}

public class Foo<T> {
    private Factory<T> factory;

    public Foo(Factory<T> factory) {
        this.factory = factory;
    }

    public T createInstance() {
        return factory.create();
    }
}

3. Поставщики Java 8: надёжные создатели экземпляров

В Java 8 представлен функциональный интерфейс Supplier<T>, который прекрасно подходит для создания экземпляров обобщённых типов.

Java
Скопировать код
import java.util.function.Supplier;

public class Foo<T> {
    private Supplier<T> supplier;

    public Foo(Supplier<T> supplier) {
        this.supplier = supplier;
    }

    public T createInstance() {
        return supplier.get();
    }
}

Визуализация

Это иллюстрация пути от абстрактного обобщённого типа к его реализации:

Markdown
Скопировать код
Generic Class<Invisible> myThing = new GenericClass<>();
👔 -> [SizeSmall, SizeMedium, SizeLarge, SizeXL]
GenericClass<SizeMedium> myPerfectShirt = new GenericClass<SizeMedium>();

Вот ваш экземпляр, идеально подходящий по типу:

Markdown
Скопировать код
Ваш выбор: [SizeMedium]

4. Риски работы с рефлексией: будьте внимательны

Помните, что работа с рефлексией может быть рискованной. Метод newInstance() может вызвать проблемы, если у T нет конструктора по умолчанию.

Java
Скопировать код
public T createInstance() 
    throws IllegalAccessException, InstantiationException {
    return type.newInstance();
}

Type mySuperclass = getClass().getGenericSuperclass();

5. Фабрики вне рамок конструкторов без параметров: расширяем возможности

Если вам нужен объект T без конструктора по умолчанию, фабрики предлагают удобное решение этого ограничения.

Java
Скопировать код
MyClass<String> myObj = new MyClass<>(String::new);

6. Стирание типов – спуск в "кроличью нору" Java

В рантайме обобщённые типы исчезают из-за стирания типов. Однако, наши стратегии помогут нам преодолеть этот нюанс с помощью вывода типов.

Java
Скопировать код
Type genericType = ((ParameterizedType)myObj.getClass().getGenericSuperclass()).getActualTypeArguments()[0];

Полезные материалы

  1. Урок: Обобщения (обновлено) (The Java™ Tutorials > Learning the Java Language) – Официальная документация Oracle по обобщениям в Java.
  2. Java generics type erasure: when and what happens? – Stack Overflow – Пояснения о стирании типов в Java на Stack Overflow.
  3. AngelikaLanger.com – Java Generics FAQs – Часто задаваемые вопросы и ответы по обобщениям в Java.
  4. Effective Java, 3rd Edition – Книга Джошуа Блоха о лучших практиках применения Java, включая обобщённые типы.
  5. Java – Generics – Учебник по обобщениям в Java с практическими примерами.
  6. Generics in Java – GeeksforGeeks – Подробное руководство по обобщённым типам с примерами использования.