Я хочу создать объект Java для класса, который определяется с помощью универсальных типов. В частности, я хочу создать список объектов класса, который определяется во время выполнения.
Я бы хотел что-то вроде
Class clazz = Class.forName("MyClass");
List<clazz> myList = new ArrayList<>(); // This isn't allowed
Определение массива объектов позволило бы мне хранить список объектов типа MyClass, но это привело бы к приведению объектов каждый раз, когда объект выбирается из списка, я бы хотел избежать такого сценария.
Есть ли способ добиться чего-то вроде приведенного выше кода с помощью java.
@LouisWasserman, но как нам привести к List <clazz>, поскольку эта структура не разрешена java, преобразование отдельных объектов с помощью Reflections простое, но можем ли мы преобразовать общий класс, используя тот же синтаксис?
Это невозможно, поскольку универсальные типы разрешаются во время компиляции, поэтому во время выполнения универсальные типы в основном не существуют. Как вы собираетесь использовать список после его объявления? В любом случае, в зависимости от того, как вы это решите, кастинг не должен вызывать беспокойства.
Вы этого не сделаете. Пишите List без дженериков. Если у вас когда-либо был Class<T>, вы можете транслировать его на List<T>.
@LouisWasserman Я бы предпочел List<?> необработанному списку. На одно предупреждение меньше.
@VGR, к сожалению, это сделает список только для чтения
@Amal J: Я действительно этого не понимаю: вы говорите, что вам нужно «приводить объекты каждый раз, когда объект выбирается из списка». Но если тип clazz неизвестен до времени выполнения, как узнать, что преобразовать к? К какому типу вы относитесь?
@Eugene Предложенный вами подход в моем случае был невозможен. В любом случае спасибо за предложение.




Что ж, поскольку вы знать этого класса, вы можете (с предупреждением) преобразовать сам List; но вам все равно нужно знать имя класса и некоторые проверки для этого, например:
if (clazz.getName().equals("java.lang.String")) {
// warning here
yourList = (List<String>) yourList;
}
Имя класса определяется во время выполнения, и это может быть множество классов, и написать такую логику для решения будет невозможно.
@AmanJ, могут ли ваши классы расширять общий интерфейс, чтобы вы могли преобразовать его в List<ThatInterface>? В противном случае приведение каждого элемента будет единственным решением.
Нет, не можешь. Обобщения в Java - это просто механизм проверки типов во время компиляции. Если вы не знаете тип до времени выполнения, то, очевидно, его нельзя использовать для проверки типа во время компиляции. Компилятор не может определить во время компиляции, какие типы разрешить вам вставлять или выходить из List<clazz>, поэтому это не более значимо, чем просто необработанный тип List.
Насколько я понимаю ваш вопрос, вы хотите знать, может ли компилятор узнать тип среды выполнения, когда он ограничен типом компиляции.
Вы не можете. И ваша гипотеза тоже неверна:
Defining an array of object would allow me to store a list of MyClass type objects, but that would lead to casting the objects every-time the object is fetched from the list, i would like to avoid such a scenario.
В Java дженерики не удаляют приведение: оно все еще присутствует в форме стирания типа и (скрытого) приведения. Когда вы выполняете List<String>, вы просто просите компилятор скрыть приведение в действии, например T get(int): будет приведение к String.
Если вы хотите использовать информацию о времени компиляции, это будет означать, что у вас уже есть / известен тип MyClass, доступный во время компиляции, и вы не будете использовать Class::forName, а MyClass.class, который вернет Class<MyClass>.
Что вы можете сделать, так это:
Driver).Class::isAssignableFrom.Есть небольшой трюк, который можно использовать для работы с определенным неизвестным типом: объявить параметр типа, который используется только для неизвестного типа:
public <T> void worksWithSomeUnknownClass() throws ReflectiveOperationException {
@SuppressWarnings("unchecked")
Class<T> clazz = (Class<T>) Class.forName("MyClass");
T obj = clazz.getConstructor().newInstance();
List<T> myList = new ArrayList<>();
myList.add(obj);
}
Однако это решение очень ограничено. Это гарантирует, что вы не перепутаете его с другими неизвестными типами или Object, но вы не можете ничего делать с T. И вы должны объявить параметр типа для каждого метода, который его использует.
«но это привело бы к преобразованию объектов каждый раз, когда объект выбирается из списка, я бы хотел избежать такого сценария». Ничто из того, что вы можете сделать, не избавит вас от необходимости каждый раз приводить объекты, кроме небезопасного приведения к списку, что не является необоснованным.