Почему универсальный идет перед возвращаемым типом?

#java

#java

Вопрос:

Мне пришлось написать эту функцию, которая использует функциональный интерфейс mapper и сопоставляет элементы стека с типом <R> . Мой вопрос в том, почему дополнительный общий перед возвращаемым типом Stack<R> необходим в функции map?

 public <R> Stack<R> map(Function<E, R> mapper) {

}
 

Ответ №1:

Класс может быть универсальным или нет, но каким бы ни был ваш класс public class MyClass , или public class MyClass<E> может случиться так, что вы хотели бы предложить метод, который использует универсальный параметр только для себя, который не используют другие методы в вашем классе.

Итак <R> , здесь :

 public <R> Stack<R> map(Function<E, R> mapper) {

}
 

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

 public <R extends Serializable> Stack<R> map(Function<E, R> mapper) {

}
 

например.


В вашем случае этот параметр используется для связывания возвращаемого вами типа с типом, который вы вводите при вводе этого метода: это гарантирует, что если вы предоставите средство отображения типа Function<E, R> , вы получите взамен объект R.


Другим удобным использованием этих «дополнительных» универсальных параметров в методах является динамическая проверка типа возвращаемого объекта. Я часто его использую :

 public <T> T myMethod(Class<T> expectedClass, int a, int b) {
...
   // My result comes in an object o.
   Object o;

   if (expectedClass.isInstance(o) == false) {
     // ClassCastException
   }

   return (T)o; // You are sure it has the expected type.
}
 

Комментарии:

1. Могу ли я добавить несколько «<R>» перед объявлением возвращаемого типа или только один?

Ответ №2:

Каждый раз, когда вы имеете дело с дженериками в Java, вы должны явно сообщить методу (и компилятору), что вы имеете дело с этим. Как сообщить им об этом таким образом, добавив <T> к сигнатуре метода.

Цитирую по ссылке ниже:

В сигнатуре метода подразумевается, что метод будет иметь дело с универсальным типом T. Это необходимо, даже если метод возвращает void

Это очень поверхностное объяснение, но вы можете прочитать больше здесь и здесь .

Ответ №3:

Первый <R> описывает тип, который вы можете использовать в сигнатуре метода, поэтому он добавляет заполнитель, который вы можете использовать (в любом случае, это список используемых типов). В Stack<R> or Function<E,R> параметр type указывает, что данный универсальный тип должен использоваться из объявленных типов.

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

 public  <T extends SomeObject amp; Comparable> Stack<T> map(T x)
 

Будет некрасиво записывать все выражение во все места, где вы хотите их использовать.
Кроме того, если вы используете его, например, как массив, вы не можете сделать это там:

 public  <T extends SomeObject amp; Comparable> Stack<T> map(T[] x)
 

Итак, первый — это объявление типа в качестве заполнителя. А остальные — это сторона использования дисперсии. Затем компилятор может проверить, что все в порядке на сайтах вызовов, прежде чем произойдет удаление типа.

Ответ №4:

Он вызывает «Универсальный метод». <R> Означает тип параметра метода, и он будет определен только при вызове метода.