Создание обобщенного метода

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

Начнем с примера. В следующей программе объявлен необобщенный класс по имени GenMethDemo и статический обобщенный метод внутри класса по имени isln (). Метод is In () определяет, является ли объект членом массива. Он может быть использован с любым типом объектов и массивов до тех пор, пока массив содержит объекты, совместимые с типом искомого объекта.

// Демонстрация простого обобщенного метода.
class GenMethDemo {
// Определение, содержится ли объект в массиве.
static <Т, V extends Т>
boolean isIn(T х, V[] у) {
for(int i=0; i < у.length; i++) if(x.equals (y [i] )
}
return true;
return false;
public static void main(String args[]) {
// Применение isln() для Integer.
Integer nums [] ={1, 2, 3, 4, 5);
if(isln (2, nums))
System.out.println ("2 содержится в nums");
if(!isln(7, nums))
System.out.println("7 не содержится в nums");
System.out.println ();
// Применение isln() для String. String strs[] = ( "один", "два", "три", "четыре", "пять" };
if(isln("два", strs))
System.out.println("два содержится в strs");
if(!isln("семь", strs))
System.out.println("семь содержится в strs");v // He скомпилируется! Типы должны быть совместимыми.
// if(isln("два", nums))
// System.out.println("два содержится в strs ") ;
}
}

Результат работы этой программы показан ниже:

2 содержится в nums
7 не содержится в nums
два содержится в strs
семь не содержится в strs

Рассмотрим isln () поближе. Для начала посмотрите, как объявлен метод в следующей строке:

static <Т, V extends Т> boolean isIn(T х, V[] у) {

Параметр типа объявлен перед типом возврата метода. Второе — тип V ограничен сверху типом Т. То есть V либо должен тем же типом, что и Т, либо типом его подклассов. Это отношение указывает, что isln () может быть вызван только с аргументами, совместимыми между собой. Также обратите внимание, что метод isln () статический, что позволяет вызывать его независимо от какого-либо объекта. Однако ясно, что обобщенные методы могут быть как статическими, так и нестатическими. Нет никаких ограничений на этот счет.

Теперь обратите внимание на то, как isln () вызывается внутри main () — с нормальным синтаксисом вызовов, без необходимости специфицировать аргументы типа. Это потому, что типы аргументов подразумеваются автоматически, и типы Т и V определяются соответственно. Например, в следующем вызове:

if(isln (2, nums))

тип первого аргумента — Integer (благодаря автоупаковке), что подставляет integer вместо Т. Базовый тип второго аргумента — также Integer, что подставляет его и вместо V.

Во втором вызове используются типы String, и вместо типов Т и V подставляются String.

Теперь обратите внимание на закомментированный код: // if(isln("два", nums))
// System.out.println("два содержится в strs ");

Если вы уберете комментарии с этих строк и затем попытаетесь скомпилировать программу, то получите ошибку. Причина в том, что тип параметра V ограничен Т конструкцией extends в объявлении V. Это значит, что V должно иметь либо тип Т, либо тип его подкласса. А в этом случае первый аргумент имеет тип String, но второй — Integer, который не является подклассом String. Это вызовет ошибку несоответствия типов во время компиляции. Такая способность обеспечивать безопасность типов — одно из наиболее существенных преимуществ обобщенных методов.

Синтаксис, использованный для создания isln (), можно обобщить. Вот синтаксис обобщенного метода:

ret-type meth-name(param-list) {
// ...

Во всех случаях type-param-list — это разделенный запятыми список параметров типа. Обратите внимание, что для обобщенного метода список параметров типа предшествует типу возврата.