JAVA - использование класса, полученного по его имени (строковое значение)

это то, что мой код выглядит, если я использую предопределенный класс:

List<MyClass> result = new ArrayList<MyClass>();
try {
    Query query = mgr.newQuery(MyClass.class);
    for(Object obj : (List<Object>) query.execute()) {
        result.add(((MyClass) obj));
    }
}
.... 
return result;

теперь мне нужно быть более общим: начиная с общего имени класса (в виде строки, то есть "TheChosenOne" ) мне нужно сделать то же самое, но я не могу понять, как выполнить роль роли..

Просто чтобы сделать пример того, что я пытаюсь сделать:

String str = "TheChosenOne"; //this value may change
Class cls;
List<Object> result = new ArrayList<Object>();
try {
    if(str.equals("TheChosenOne"))
        cls = Class.forName("com.blabla.TheChosenOne");
    else if(str.equals("Rabbit"))
        cls = Class.forName("com.blabla.Rabbit");
    else if(str.equals("Batman"))
        cls = Class.forName("com.heroes.Batman");
    else
        cls = null;

    if(cls != null){
        Query query = mgr.newQuery(MyClass.class);
        for(Object obj : (List<Object>) query.execute()) {
            result.add(((???) obj)); //I need help here!
        }
    }
}
...
return result;

Я взял "Class.forname()..." часть здесь.

Любые предложения? Спасибо заранее, наилучшие пожелания

Ответ 1

То, что вы пытаетесь сделать, не нужно, потому что ваш список объявлен как List<Object>, поэтому приведение не требуется.

- Перед редактированием -

Не уверен, что я понимаю, что вам нужно, но вы пытались использовать:

Class.cast(object)

Это метод java.lang.Class

Ответ 2

Я думаю, что то, что вы пытаетесь сделать, может быть достигнуто с помощью генериков.

Например, такой метод:

     public <E> List<E> getList(Class<E> clazz) {
         List<E> result = new ArrayList<E>();
         if(clazz != null){
             Query query = mgr.newQuery(MyClass.class);
             for(E obj : (List<E>)query.execute()) {
                 result.add(obj); 
             }
         }

         return result;
     }

Можно вызвать с помощью:

 getList(TheChosenOne.class)

И он вернет объект List<TheChosenOne>

Ответ 3

Если result - это List<Object>, вам вообще не нужен бросок, просто add(obj) будет работать нормально.

Если вам нужна безопасность типа времени компиляции, вам придется передать объект Class, а не строку, содержащую его имя, и использовать подпись общего метода

public <T> List<T> doQuery(Class<T> theClass) {
  List<T> result = new ArrayList<T>();
  try {
    Query query = mgr.newQuery(theClass);
    for(T obj : (List<T>) query.execute()) {
      result.add(obj);
    }
  }
  .... 
  return result;
}

Если вы пройдете этот маршрут и имеете возможность модифицировать класс Query, тогда вы можете захотеть сделать этот параметр параметрированным

public class Query<E> {
  public List<E> execute() { ... }
}

// and in mgr
public <T> Query<T> newQuery(Class<T> cls)

который затем позволит вам сказать

    Query<T> query = mgr.newQuery(theClass);
    for(T obj : query.execute()) {
      result.add(obj);

без литья вообще.

Ответ 4

Я считаю, что cls.cast(obj) - это то, что вы ищете.

Ответ 5

Я думаю, вам нужно сделать это следующим образом: используя оператор instance of, чтобы проверить тип класса, а затем выполните листинг типов

for(Object obj : (List<Object>) query.execute()) {
  if(obj instance of Batman)
    result.add(((Batman) obj));
  else if(obj instance of Cat)
    result.add(((Cat) obj));

  // and so on
  ...
  ...
}

Ответ 6

Вам не нужно бросать, помещая объект в ArrayList,

 result.add(obj); 

Если вы хотите, чтобы вы могли использовать его при получении из списка

 cls .cast(result.get(1));