Как избежать небезопасных приведений с помощью Java Generics - PullRequest
0 голосов
/ 29 февраля 2012

Я совершенно новичок в Java Generics. Но я прочитал много кратких ссылок и примеров. Но я не могу понять самый простой способ. Надеюсь соменое может помочь:

Я хочу создать HashMap, который отображает один неопределенный объект на другой. Оба объекта могут быть одним из String или Integer.

Итак, я написал это:

private final HashMap<L, R> left2Right = new HashMap<L, R>();

Extractor<?> extLeft  = Extractor.getInstance(0);
Extractor<?> extRight = Extractor.getInstance(1);

L leftVal = extLeft.extract(d, i);
R rightVal = extRight.extract(d, i);

this.left2Right.put(leftVal, rightVal);

Пока все хорошо ... Но у меня проблемы с реализацией объектов экстрактора. Они воплощены фабричным образцом. Я сделал это так (просто):

abstract class Extractor<E> {
    abstract E extract(DTable source, int row);

    static <E> Extractor<E> getInstance(int type) {
        if(type == 0)
            return new IntExtractor();
        else
            return new StringExtractor();
    }
}

class IntExtractor extends Extractor<Integer> {

    @Override
    Integer extract(DTable source, int row) {
        int value = 5;
        return new Integer(value);
    }

}

class StringExtractor extends Extractor<String> {

    @Override
    String extract(DTable source, int row) {
        String retVal = "hello";
        return retVal;
    }

}

Он компилируется, но я получаю Unsave предупреждения при приведении Integer / String к E. Что я делаю не так? Я знаю, я могу просто подавить предупреждения. Но я думал, что именно это должно быть преимуществом дженериков Java? Я не могу сохранить этот бросок, потому что я не знаю, какой тип 'E' действительно "есть" ...

Или я что-то делаю в принципе неправильно?

Примечание: Я изменил свой код для «нового» вопроса после того, как использовал некоторую информацию из первого ответа ...

Ответы [ 4 ]

2 голосов
/ 29 февраля 2012

Ваши экстракторы на самом деле не являются общими.Звучит так, будто вы хотите что-то вроде:

public interface Extractor<P> {
    P extract(DTable source, int row);
}

, но затем сделайте реализации неуниверсальными:

class IntExtractor implements Extractor<Integer> {

    Integer extract(DTable source, int row) {
        int value = 5;
        return new Integer(value);
    }
}

По сути, ваш текущий код не работает, в этомЯ мог бы написать:

IntExtractor<String> extractor = new IntExtractor<String>();
String x = extractor.extract(...);

... что, очевидно, не получится, но только во время выполнения.

1 голос
/ 29 февраля 2012

Проблема не в вашем коде как таковом. Сама задача не может быть решена без небезопасных забросов. Прочитайте свое собственное предложение еще раз:

Я хочу создать HashMap, который отображает один undefined объект на другой. Оба объекта могут быть одним из String или Integer.

Java Generics не может решить эту проблему за вас, потому что вы должны знать тип заранее, в противном случае вам придется разыграть.

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

private final HashMap<String, Integer> left2Right = new HashMap<String, Integer>();
left2Right.put("one", 1);
int numberOne = left2Right.get("one");

В этом случае вам не нужно приводить значения, потому что HashMap имеет строковые ключи и целочисленные значения. Если вы хотите поместить разные типы в качестве значений, вы должны использовать супертип всех значений. Этот супертип может быть Object, корнем иерархии. Но в этих случаях вам нужно разыграть, потому что вы не знаете, какой объект имеет значение.

    private final HashMap<String, Integer> left2Right = new HashMap<String, Object>();
    left2Right.put("one", 1);
    left2Right.put("two", new Date());
    // Because the compiler cannot know that type "one" might be, this isn't allowed and     you have to cast the value. It might be anything - in this example Date or Integer.
    int numberOne = left2Right.get("one");

Надеюсь, это поможет.

1 голос
/ 29 февраля 2012

Я бы сказал, что вы делаете что-то в принципе неправильно.Если это IntExtractor и StringExtractor, вам не нужны дженерики.Просто определите методы

Integer extract(DTable source, int row)

и

String extract(DTable source, int row)
0 голосов
/ 29 февраля 2012

И P, и E, похоже, не используются для ввода экстракторов, так почему вы их даже имеете?Просто верните int и String и покончите с этим.

...