Подтвердить что ты не робот

Что такое использование генериков в Java? Х <Y>() метод

Я прочитал всю книгу SCJP6 "Книга Сьерра и Бейтса", набрал 88% экзамена.

Но все же я никогда не слышал о том, как работает этот код, поскольку он не объясняется в главе generics:

Collections.<TimeUnit>reverseOrder()

Что такое использование дженериков? Я обнаружил это в некотором коде, но ничего не читал об этом. Мне кажется, это позволяет дать некоторую помощь для ввода вывода. Я попытался найти об этом, но его не так просто найти (и это даже не в книге/экзамене SCJP!)

Так может ли кто-нибудь дать мне правильное объяснение того, как это работает, и все это - это usecases и т.д.

Спасибо


Edit Спасибо за ответы, но я ожидал более подробной информации:), поэтому, если кто-то хочет добавить дополнительную информацию:

Как насчет более сложных случаев типа

  • Используя тип, объявленный в классе, могу ли я сделать что-то вроде Collections.<T>reverseOrder() для примера?
  • Используя extends, super?
  • Использование ?
  • Предоставление компилятору только частичной справки (т.е. O.manyTypesMethod<?,MyHelpTypeNotInfered,?,?,?,?,?>())
4b9b3361

Ответ 1

Это явная спецификация типа общего метода. Вы всегда можете это сделать, но в большинстве случаев это не нужно. Тем не менее, в некоторых случаях требуется, чтобы компилятор не смог самостоятельно вывести общий тип.

См. пример в конце страницы руководства.

Обновление: действителен только первый из ваших примеров. Явный аргумент типа должен быть, ну, явным, поэтому никаких подстановочных знаков extends или super не допускается. Более того, либо вы указываете каждый аргумент типа явно, либо ни один из них; то есть количество аргументов явного типа должно соответствовать количеству параметров типа вызываемого метода. Параметр типа, такой как T, разрешен, если он хорошо определен в текущей области, например. как параметр типа охватывающего класса.

Ответ 2

Вы на 100% правильны, это поможет с типом вывода. В большинстве случаев вам не нужно делать это на Java, поскольку он может вывести тип (даже с левой стороны задания, что довольно круто). Этот синтаксис рассмотрен в учебнике по обобщениям на веб-сайте Java.

Ответ 3

Просто небольшое дополнение к другим ответам.

При получении соответствующей ошибки компилятора:

В то время как "традиционный" подход к литью

(Comparator<TimeUnit>) Collections.reverseOrder()

похож на общий подход

Collections.<TimeUnit>reverseOrder()

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

Ответ 4

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

Например, рассмотрим методы Collections.empty*, которые возвращают пустую коллекцию. Если у вас есть метод, ожидающий Map<String, String>:

public static void foo(Map<String, String> map) { }

Вы не можете напрямую передать Collections.emptyMap(). Компилятор будет жаловаться, даже если он знает, что он ожидает Map<String, String>:

// This won't compile.
foo(Collections.emptyMap());

Вы должны явно объявить тип, который вы хотите в вызове, который, по моему мнению, выглядит довольно уродливо:

foo(Collections.<String, String>emptyMap());

Или вы можете опустить это объявление типа в вызове метода, если назначить возвращаемое значение emptyMap переменной перед тем, как передать его в функция, которая, по моему мнению, довольно смехотворна, потому что она кажется ненужной, и она показывает, что компилятор действительно непоследователен: он иногда делает вывод типа для общих методов без параметров, но иногда это не так:

Map<String, String> map = Collections.emptyMap();
foo(map);

Это может показаться не очень важной вещью, но когда общие типы начинают усложняться (например, Map<String, List<SomeOtherGenericType<Blah>>>), один из способов начать с того, что Java будет иметь более интеллектуальный вывод типа (но, как нет, один, вероятно, начнет писать новые классы там, где это не нужно, просто чтобы избежать всех этих уродливых <>= D).

Ответ 5

В этом случае это способ сообщить методу reverseOrder, какой порядок заказа должен быть наложен на объект, в зависимости от того, какой тип вы укажете. Компаратор должен получить конкретную информацию о том, как упорядочить вещи.