Как я могу сделать Java, чтобы определить правильный тип карты для литералов моей безопасной карты? - PullRequest
4 голосов
/ 04 августа 2011

Я пытаюсь написать в java класс вспомогательного литерала типизированной карты, который может генерировать карты любого типа и заставить компилятор проверить, что все заданные ключи и значения соответствуют типу карты.Для карты с двумя значениями была бы функция со следующей подписью:

public static <KEY, VALUE> Map<KEY, VALUE> make(final KEY key1,
        final VALUE value1,
        final KEY key2,
        final VALUE value2)

Теперь я ожидал, что что-то подобное будет возможно:

    Map<Integer, Object> map = make(1, "bla", 3, 17);

Однако я получаюошибка компилятора:

Type mismatch: cannot convert from Map<Integer,Object&Serializable&Comparable<?>> to 
 Map<Integer,Object>

Есть ли способ исправить это?Конечно, определение функции с сигнатурой make(Object... keysAndValues) будет работать, но я потеряю безопасность типов времени компиляции.: - (

Ответы [ 6 ]

6 голосов
/ 04 августа 2011

Ошибка, вероятно, здесь:

Map<Integer, Object> map = make(1, "bla", 3, 17);
                                   ^^^^^     ^^

VALUE > Object не может быть выведено из String и Integer

Попробуйте любое из этих:

// Helping the compiler to infer Object for VALUE
Map<Integer, Object> map = make(1, (Object)"bla", 3, 17);

// Explicitly bind VALUE to Object
Map<Integer, Object> map = MyClass.<Integer, Object>make(1, "bla", 3, 17);

// If you don't need to write into "map" (as user pmnt also suggested)
Map<Integer, ?> map = make(1, "bla", 3, 17);
3 голосов
/ 04 августа 2011

Ваш код будет работать, если вы измените подпись Карты в методе вызова:

Не требуется никаких изменений для make

public static <A, B> Map<A, B> make(final A key1, final B value1,
        final A key2, final B value2) {
    Map<A, B> map = new HashMap<A, B>();
    map.put(key1, value1);
    map.put(key2, value2);
    return map;
}

*Абонент 1010 *

Вы должны изменить Map<String, Object> на Map<String, ? extends Object>:

public static void main(String[] args) {

    @SuppressWarnings("unused")
    Map<String, ? extends Object> m = make("a", new Integer(1), "2", "efg");

}

EDIT1: OpenJDK 1.6 + Eclipse Indigo compiler

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

EDIT3: Есть ли способ исправить это?Конечно, определение функции с помощью сигнатуры make (Object ... keysAndValues) будет работать, но я бы потерял безопасность типов времени компиляции.

Вы всегда потеряете безопасность времени компиляции в определенный момент.По крайней мере, когда дело доходит до поиска.

2 голосов
/ 04 августа 2011

Это компилируется:

Map<Integer, ? extends Serializable> map = make(1, "bla", 3, 17);

Это то, что дает вам вывод общего типа Java.Не то, что вы ожидали?

У вас есть пара опций, либо используйте метод для пояснения:

Map<Integer, Object> map = Util.<Integer, Object>make(1, "bla", 3, 17);

Или вы можете использовать объекты, которые не имеют общего родительского интерфейса.

Map<Integer, Object> map = make(1, "bla", 3, new Object());
1 голос
/ 04 августа 2011

Компилятор должен «угадать» типы KEY и VALUE по заданным параметрам (типы ваших Map, в которых вы храните возвращаемое значение, игнорируются). «Угадай» для VALUE - самый строгий тип, подходящий как для Integer, так и для String: все, что реализует Comparable и Serializable (Object&Serializable&Comparable<?>).

У вас есть два варианта: приведение хотя бы одного ЗНАЧЕНИЯ к объекту:

Map<Integer, Object> map = make(1, (Object)"bla", 3, 17);

или использование подстановочного знака на вашей карте

Map<Integer, ?> map = make(1, "bla", 3, 17);
0 голосов
/ 15 августа 2011

Следующее решение выглядит так, как будто оно должно работать, но странно, что оно работает только в компиляторе Eclipse, но не на обычном компиляторе Java 6.8- {Почему ???

Объявление метода раздражающе сложно, но допускает простейший синтаксис при создании карт:

public static <KEY, AKEY extends KEY, VALUE, AVALUE extends VALUE> Map<KEY, VALUE> make2(final AKEY key1,
        final AVALUE value1,
        final AKEY key2,
        final AVALUE value2)

Здесь компилятор выводит из контекста в

Map<Integer, Object> map = make(1, "bla", 3, 17);

что KEY должно быть Integer, а VALUE должно быть Object;AKEY выводится из заданных параметров как Integer и AVALUE как Object & Serializable & Comparable, и компилятор может проверить, что AKEY соответствует KEY, а AVALUE - VALUE.

0 голосов
/ 04 августа 2011

String фактически реализует как Serializable, так и Comparable интерфейс, а Object нет ... поэтому его высказывание Object не реализует, но его имплицит typeCasted String делает ...

...