Я объясню это простым способом.
Обобщения, определенные на уровне класса, полностью отделены от обобщения, определенного на (статическом) уровне метода.
class Greet<T> {
public static <T> void sayHello(T obj) {
System.out.println("Hello " + obj);
}
}
Когда вы видите приведенный выше код где-либо, обратите внимание, что T, определенный на уровне класса, не имеет ничего общего с T, определенным в статическом методе. Следующий код также полностью действителен и эквивалентен приведенному выше коду.
class Greet<T> {
public static <E> void sayHello(E obj) {
System.out.println("Hello " + obj);
}
}
Почему статический метод должен иметь свои собственные обобщения, отличные от обобщенных классов?
Это потому, что статический метод может быть вызван даже без создания экземпляра класса. Поэтому, если класс еще не создан, мы еще не знаем, что такое T. Именно поэтому статические методы должны иметь свои собственные обобщения.
Итак, всякий раз, когда вы вызываете статический метод,
Greet.sayHello("Bob");
Greet.sayHello(123);
JVM интерпретирует это следующим образом.
Greet.<String>sayHello("Bob");
Greet.<Integer>sayHello(123);
Оба дают одинаковые выводы.
Hello Bob
Hello 123