Дженерики и рефлексия Java - PullRequest
       17

Дженерики и рефлексия Java

3 голосов
/ 04 декабря 2011

Я пишу небольшой класс и столкнулся с проблемой.

Этот класс читает файл CSV, для каждого ключа будет только одно значение.У меня есть

class CSVMap<T> extends AbstractMap<String,T>

, и у меня есть:

public void load(String filename)
{
    try 
    {
        BufferedReader out=new BufferedReader(new FileReader(filename));
        String []tab;
        T value;

        while(out.ready());
        {
            tab=out.readLine().split(",");


        }
    } catch (IOException e) 
    {
        e.printStackTrace();
    }
}

Теперь мне нужно создать новые экземпляры T, чтобы поместить их в мою карту (я знаю, что T имеет конструктор, который принимает строку).

Я знаю о стирании типов в Java, поэтому единственным выходом из этого является а) передача T.Class моему методу load или сохранение его где-то в частном порядке в моем классе или b) сохранение некоторого частного объекта T и использованиеэто в методе, чтобы получить объект класса?

Я спрашиваю, потому что я хотел быть уверен, что нет другого способа сделать это.

Ответы [ 3 ]

2 голосов
/ 04 декабря 2011

Есть еще один способ, который вы можете рассмотреть. Это заставляет ваш CSVMap принимать в качестве параметра для своего конструктора объект, который знает, как преобразовать из класса в другой класс.

например.

public class Test {

    public static void main(String[] args) {
        CSVMapLoader<Integer> loader = new CSVMapLoader<Integer>(new IntegerParser());
        loader.load();
    }

}

class CSVMapLoader<T> {

    private final Parser<T> parser;

    public Loader(Parser<T> parser) {
        this.parser = parser;
    }

    public CSVMap<T> load() {
            // as an example of how to get your T
        T t = parser.parse("1000");
        System.out.println("t equal to 1000? "+(t.equals(1000)));
            // and instead put your real logic to load up map here
    }
}

interface Parser<T> {
    public T parse(String str);
}

class IntegerParser implements Parser<Integer> {

    public Integer parse(String str) {
        return Integer.valueOf(str);
    }
}

Как примечание к дизайну кода. Вы не должны действительно подкласс (Абстракт) Карта в этом случае. Вам нужен класс, который знает, как загрузить пары ключ-значение из файла CSV. Интерфейс Map - это просто сохранение и доступ к этим парам после загрузки. Поэтому на самом деле вам нужен отдельный класс фабрики, который принимает файл, парсер и, возможно, базовый тип карты и загружает карту для вас. Оставив вас с нетронутым экземпляром карты, не зная, как он был загружен.

1 голос
/ 04 декабря 2011

Нет, вы правы.Нет абсолютно никакого способа восстановить параметр типа T во время выполнения, если вы не передали объект Class в экземпляр метода экземпляра во время выполнения.Другой стратегией, которую вы могли бы попробовать, было бы передать фабричный объект в load () или в CSVMap.Это избавило бы от необходимости знать фактический класс из CSVMap и возложило бы на него ответственность вызывающего объекта (зная реализацию фабрики).

Различные библиотеки имеют свои собственные глупые обходные пути для этой проблемы.Особенно умный включен в Google Guice.Проверьте http://google -guice.googlecode.com / git / javadoc / com / google / inject / TypeLiteral.html .Он использует тот факт, что параметризованный класс ДОЛЖЕН сохранять параметры своего типа, когда он подклассируется с использованием конкретных параметров типа.Так что вы можете сделать:

TypeLiteral<List<String>> typeLiteral = new TypeLiteral<List<String>>() {};
typeLiteral.getType().toString(); // returns "java.util.List<java.lang.String>"
0 голосов
/ 04 декабря 2011

Нет, другого пути нет.Я бы передал Class объект

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