Странный универсальный Java

Что это значит?

HashBiMap<Character, Integer> charOcc = HashBiMap.<Character, Integer> create();

person nanda    schedule 12.01.2010    source источник
comment
В самом деле, это даже необходимо? Я думаю, что компилятор должен уметь выводить параметры универсального типа с левой стороны.   -  person Michael Myers    schedule 12.01.2010
comment
Должен, но не будет. В Java вы должны объявить абсолютно все.   -  person mcv    schedule 12.01.2010
comment
@mcv - вы ошибаетесь - компилятор может вывести типы с левой стороны.   -  person McDowell    schedule 12.01.2010
comment
Коллекции Google используют этот факт в своих служебных классах, если я правильно помню. Map<Character, Integer> myMap = Maps.newHashMap();   -  person Michael Myers    schedule 12.01.2010
comment
На самом деле HashBiMap взят из коллекций Google, и этот метод существует специально, поэтому вам не нужно писать параметры типа справа при создании его экземпляра.   -  person ColinD    schedule 12.01.2010
comment
Я часто вижу это при использовании Arrays.asList(), поскольку это наиболее распространенный метод, который я использую, который имеет общий статический метод. См. класс Arrays для сигнатуры метода.   -  person RNJ    schedule 05.12.2012


Ответы (6)


create() — это общий метод. Поскольку он статичен и не имеет параметров (следовательно, нет вывода о типе), единственный способ, которым вы можете сказать ему, что такое общие параметры, — это странный синтаксис .<Character, Integer>.

Редактировать: в данном конкретном случае в этом нет необходимости; компилятор может вывести общие типы с левой стороны. Но иногда это необходимо в других случаях, таких как этот вопрос: Универсальный метод в Java без общего аргумента

person Michael Myers    schedule 12.01.2010

Он вызывает универсальный статический метод (create()), используя Character и Integer в качестве аргументов типа. Например, если вы просматриваете коллекции Google Java, объявление имеет следующую подпись:

public static <K,V> HashBiMap<K,V> create()

Часть <K,V> сама по себе указывает, что это параметры типа для метода.

Эквивалентный вызов в C# будет одним из:

HashBiMap.Create<Character, Integer>();
HashBiMap<Character, Integer>.Create();

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

Позиционирование параметров типа и аргументов типа в Java неинтуитивно, IMO.

person Jon Skeet    schedule 12.01.2010
comment
с другой стороны, структура вызывающего кода следует структуре определения - сначала параметры типа, потом имя метода. - person Bozho; 12.01.2010
comment
@Божо: Но позиция относительно точки странная, и мне это тоже не нравится в определении :) - person Jon Skeet; 12.01.2010
comment
@Downvoter: Вы проголосовали против, потому что я выразил неприязнь к синтаксису Java, или потому что вы думаете, что я сказал что-то неточное? - person Jon Skeet; 12.01.2010

Это означает, что метод static create() имеет параметры типа, например:

public static <Character, Integer> HashBiMap<Character, Integer> create() {..}
person Bozho    schedule 12.01.2010

Предположительно, это правая сторона (RHS), которую вы считаете странной.

HashBiMap.<Character, Integer> create();

Обычно необходимо использовать только параметры типа в LHS при вызове универсального статического метода. Но иногда статический метод не выводит параметры типа так, как вы предполагали. В этих случаях вы также можете использовать параметры типа в RHS, чтобы привести параметры типа к тому, что вы намеревались. Это известно как параметр явного типа.

Вот пример того, когда параметры типа не выводятся правильно (адаптировано из отличной книги "Effective Java"):

Пример

Учитывая статический метод

public static <E> Set<E> union(Set<? extends E> s1, Set<? extends E> s2)

вы можете подумать, что можете сделать это:

Set<Integer> integers = ... ;
Set<Double> doubles = ... ;
Set<Number> numbers = union(integers, doubles);

Если вы попробуете это, вы получите это сообщение об ошибке:

Union.java:14: incompatible types
found : Set<Number & Comparable<? extends Number & Comparable<?>>>
required: Set<Number>
    Set<Number> numbers = union(integers, doubles);

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

Set<Number> numbers = Union.<Number>union(integers, doubles);
person Dónal    schedule 12.01.2010

HashBiMap, вероятно, имеет метод

public static <K,V> HashBiMap<K,V> create(){...}

Использование синтаксиса

HashBiMap<Character, Integer> charOcc = HashBiMap.<Character, Integer> create();

вы передаете символ для K и целое число для V.

person Tobias Schulte    schedule 12.01.2010

Если вы хотите избежать громоздкого синтаксиса предоставления формальных параметров, вы можете использовать приведение для ввода подсказки.

Используя ваш пример,

Set<Integer> integers = ... ;
Set<Double> doubles = ... ;
Set<Number> numbers = union((Set<Number>)integers, doubles);

Это будет принято компилятором и позволит избежать использования

Set<Number> numbers = Union.<Number>union(integers, doubles);
person Jonathan Weatherhead    schedule 03.09.2011