Как получить универсальный тип во время выполнения? - PullRequest
9 голосов
/ 15 октября 2010

Это мой код: ExecutorImp расширяет AbstractExecutor, который извлекает ту же логику выполнения из своих реализаторов (ExecutorImp является одним из случаев), при вызове метода execute () класса ExecutorImp он будет вызывать метод в своем супертипе, но в супертипе(AbstractExcutor) должен знать другую привязку класса к реализатору (в примере это класс User):

import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;

abstract class AbstractExecutor<E> {
    public void execute() throws Exception {
        ArrayList<E> list = new ArrayList<E>();
        // here I want to get the real type of 'E'
        Class cl = this.getClass().getTypeParameters()[0].getGenericDeclaration().getClass();
        Object o = cl.getConstructor(String.class).newInstance("Gate");
        list.add((E) o);
        System.out.println(format(list));
    }
    public abstract String format(ArrayList<E> list);
    public abstract String getType();
}

public class ExectorImp<E> extends AbstractExecutor<User> {
    @Override
    public String getType() {
        return "user";
    }
    @Override
    public String format(ArrayList<User> list) {
        StringBuffer sb = new StringBuffer();
        for (User u : list) {
            sb.append(u.toString() + " ");
        }
        return sb.toString();
    }
    public static void main(String[] args) throws Exception {
        new ExectorImp().execute();
    }
}
class User {
    String name;
    public User(String name) {
        this.name = name;
    }
}

ТАК, в чем проблема с моими кодами?

Ответы [ 4 ]

14 голосов
/ 15 октября 2010

Здесь есть некоторая путаница.Из-за удаления типа вы не можете получить информацию о типе из параметризованного типа во время выполнения, например:

Class<E> cls = E.getClass(); // Error.
E e = new E(); // Error.

Однако вы можете получить информацию о параметризованном типе во время компиляции из объявления класса, поля и метода с помощью ParameterizedType#getActualTypeArguments().

abstract class AbstractExecutor<E> {

    public void execute() throws Exception {
        List<E> list = new ArrayList<E>();
        Class<E> cls = (Class<E>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
        E e = cls.getConstructor(String.class).newInstance("Gate");
        list.add(e);
        System.out.println(format(list));
    }

    // ...
}

Обновление : относительно того, рекомендуется это или нет, хотя это будет работать, это чувствительно к проблемам времени выполнения всякий раз, когда незначительные изменения в классеобъявление происходит.Вы, как разработчик, должны документировать это правильно.В качестве совершенно другой альтернативы вы можете использовать полиморфизм.

abstract class AbstractExecutor<E> {

    public void execute() throws Exception {
        List<E> list = new ArrayList<E>();
        E e = create("Gate");
        list.add(e);
        System.out.println(format(list));
    }

    public abstract E create(String name);

    // ...
}

и реализовать UserExecutor соответственно.

class UserExecutor extends AbstractExecutor<User> {

    @Override
    public User create(String name) {
        return new User(name);
    }

    // ...
}
6 голосов
/ 15 октября 2010

Я думаю, вы должны использовать getActualTypeParameters;поскольку getTypeParameters относится не к тому, что было помещено в текущем экземпляре вместо E, а к E (чтобы описать, как оно ограничено и т. д.).

Для того, чтобыполучите ParameterizedType, вы должны сначала использовать getGenericSuperclass.

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

class StringList extends ArrayList<String> {
    public Type whatsMyGenericType() {
        return ((ParameterizedType)getGenericSuperClass()).getActualTypeParameters()[0];
    }
}

должен вернуть String.class.

2 голосов
/ 15 октября 2010

Не думаю, что вы можете получить универсальный тип во время выполнения.Универсальный тип - это ограничение, которое применяется во время компиляции.Как я помню, во время выполнения нет никакой разницы между универсальной коллекцией и коллекцией без универсального типа.

1 голос
/ 15 октября 2010

Обычный подход к решению проблемы - немного изменить код.Определите конструктор для базового класса, принимающего параметр Class<E>.Присвойте этот параметр внутреннему полю.

В подклассе определите конструктор без параметров и оттуда вызовите super(User.class).

Таким образом, вы узнаете класс аргумента без особой нагрузки для клиентов подклассов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...