Универсальный конструктор универсального класса

#java #generics

#java #обобщения

Вопрос:

У меня есть универсальный класс ConsumerTest<T, U> , и я планирую, что T это изменяемый тип и U эквивалентный неизменяемый тип, такой как <StringBuilder, String> , <MutableInt, Integer> , <MutableDouble, Double> , … Как я могу написать универсальный конструктор, который создает изменяемый тип из неизменяемого? Вот моя попытка:

 import org.apache.commons.lang3.mutable.MutableDouble;
import org.apache.commons.lang3.mutable.MutableInt;

class ConsumerTest<T, U> {

private T value;

public <T, U> ConsumerTest(U u) {
        this.value = new T(u);  // compile error
}

public static void main(String[] args) {
        ConsumerTest ctS = new ConsumerTest<StringBuilder, String>("Hello");
        ConsumerTest ctI = new ConsumerTest<MutableInt, Integer>(666);
        ConsumerTest ctD = new ConsumerTest<MutableDouble, Double>(11.11);
}

}
 

Комментарии:

1. Вы не можете динамически создавать универсальные типы таким образом

2. Рассмотрите возможность передачи в a java.util.Function , который действует как конструктор.

Ответ №1:

new T(u) недопустимо, поскольку T не является типом. Чтобы создать экземпляр класса, вам нужно знать тип, а вы этого не делаете в этом контексте.

Ответ №2:

Как указано в другом ответе, new T(u) недопустимый синтаксис. Нельзя использовать параметр типа в качестве нового класса для создания экземпляра, потому что нет гарантии, что конструктор этого конкретного класса принимает ровно один аргумент этого точного типа.

Кроме того, вы создали универсальный конструктор, который определяет свой собственный T и U , который затеняет объявления класса T and U . Вот почему вы получаете сообщение об ошибке компилятора, такое как «Невозможно преобразовать T в T». Удалите объявления T и U из конструктора, но не из класса.

Вам все равно нужно иметь возможность создавать объект типа T из объекта типа U , поэтому предоставьте функцию преобразования. Обратите внимание, что Java, встроенная в Function s, меняет смысл U и T , который у вас есть.

 class ConsumerTest<T, U> {

    private T value;

    public ConsumerTest(U u, Function<U, T> converter) {
        this.value = converter.apply(u);
    }

    public static void main(String[] args) {
        ConsumerTest ctS = new ConsumerTest<StringBuilder, String>("Hello", StringBuilder::new);
        ConsumerTest ctI = new ConsumerTest<MutableInt, Integer>(666, MutableInt::new);
        ConsumerTest ctD = new ConsumerTest<MutableDouble, Double>(11.11, MutableDouble::new);
    }
}
 

Могут быть дополнительные причины, по которым вам необходимо инкапсулировать эту функциональность в класс, который вы не показали, но вам может не понадобиться такой класс, как ConsumerTest . Просто создайте функции.

 Function<String, StringBuilder> ctS = StringBuilder::new;
 

Или вам, возможно, вообще не нужно беспокоиться о функциях. Создавайте изменяемые объекты напрямую.

 StringBuilder sb = new StringBuilder("Hello");
 

Комментарии:

1. Отличный ответ, спасибо за вашу помощь. Теперь все работает.