Сейчас активно изучаю (или даже разбираю) известное пособие Хорстмена и Корнелла по Java2. В данный момент остановился на параметризации. Дошел до пункта "Обобщенные методы" и следующий за ним "Ограничения переменных типов". И в ближайшем листинге среди прочего кода появляется такая сигнатура:
public static <T extends Comparable> Pair<T> minmax(T[] a)
Я понимаю, что в методе применяется метод compareTo(), принадлежащий интерфейсу Comparable и поэтому мы должны "защитить" наш метод от того, чтобы туда не затесался класс, который не реализует данный интерфейс. Ок, понятно. Но почему бы тогда нельзя было написать:
public static Pair<T extends Comparable> minmax(T[] a)
С другой стороны, возможно имелось в виду, что это не объект класса Pair должен возвращать метод, а объект любого класса, реализующий Comparable? Тогда почему не написать так:
public static <T extends Comparable> T minmax(T[] a)
?
Я не отрицаю, что в пособии вполне может быть указана правильная сигнатура. И если это так, то прошу подробно описать ее. Заранее спасибо за развернутые ответы!
Вы хотите развёрнутых ответов? Их есть у меня! Немного теории по параметризованным методам.
Если метод нестатический, а класс - параметризованный, то параметр типа наследуется из описания класса:
public class A<T> {
pubic void doSth(T t) { // метод принимает аргумент типа T
System.out.println(t.getClass().getName());
}
}
new A<String>().doSth("abc"); // выведет java.lang.String
new A<String>().doSth(123); // не скомпилируется
Если метод статический, то унаследовать параметр типа от класса он не может. Это вызвано тем, что параметр типа привязывается к конкретному объекту при его создании, а статический метод не привязан к конкретному объекту, он привязан к классу в целом. В случае статического метода параметр типа нужно указывать непосредственно перед объявлением метода:
public class A {
public static <T> void doSth(T t) {
System.out.println(t.getClass().getName());
}
}
A.doSth("abc"); // выведет java.lang.String
A.doSth(123); // выведет java.lang.Integer
В этом случае тип T
определяется в момент вызова статического метода по типу передаваемого аргумента.
Ещё один случай, когда может понадобиться явно параметризовать метод - это нестатический метод, параметр типа которого должен отличаться от параметра типа класса:
public class A<T>
{
T t;
public A(T t) {
this.t = t;
}
public <Z> void doSth(Z z) {
System.out.println(t.getClass().getName());
System.out.println(z.getClass().getName());
}
}
new A<String>("abc").doSth(123); // выведет java.lang.String
// java.lang.Integer
Если в момент компиляции вычислить тип параметра метода невозможно, необходимо явно указать его при вызове. Такие случаи очень редки, поэтому пример несколько синтетический:
public class A
{
public static void printValue(String val) {
System.out.println("String");
}
public static void printValue(Integer val) {
System.out.println("Integer");
}
public static <T> T getValue() {
return null;
}
}
A.printValue(A.getValue()); // не скомпилируется - неясно, какую
// перегрузку printValue вызывать
A.printValue(A.<String>getValue()); // выведет String
A.printValue(A.<Integer>getValue()); // выведет Integer
Теперь непосредственно к вашему вопросу. Нельзя просто написать
public static Pair<T extends Comparable> minmax(T[] a)
потому что Java не знает, что за тип T
. Java не может унаследовать его от объявления класса (даже если класс параметризован), так как метод minimax
статический. Поэтому нужно явно прописывать параметр типа в сигнатуре метода:
public static <T extends Comparable> Pair<T> minmax(T[] a)
Почему нельзя написать
public static <T extends Comparable> T minmax(T[] a)
? Можно, это корректная сигнатура метода. Однако, судя по названию метода, он должен возвращать одновременно минимальное и максимальное значение переданного массива. Поэтому метод возвращает объект класса Pair<T>
, который содержит в себе два значения.
Сигнатура абсолютна верна.
Первый предложенный вами вариант исключается, потому что в статическом методе нельзя использовать типы, определенные в классе. Вам этого не позволит компилятор.
Второй вариант нелогичен, т.к. метод возвращает пару значений (min, max)
, а для этого нужен какой-то контейнер, например Pair
. В данном случае предполагается, что оба элемента в кортеже имеют одинаковый тип.
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Во время написания программы у меня возник вопрос, ответ на который я не смог найтиЯ замеряю время выполнения одной функции в наносекундах...