Я поясню це простим способом.
Генерики, визначені на рівні класу, повністю відокремлені від дженериків, визначених на рівні (статичного) методу.
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);
}
}
Чому статичному методу потрібно мати власні дженерики, окремі від класів?
Це тому, що статичний метод можна викликати, навіть не ініціюючи клас. Тож якщо Клас ще не встановлений, ми ще не знаємо, що таке Т. Це причина, чому статичним методам потрібно мати власні дженерики.
Отже, кожного разу, коли ви викликаєте статичний метод,
Greet.sayHello("Bob");
Greet.sayHello(123);
JVM трактує це наступним чином.
Greet.<String>sayHello("Bob");
Greet.<Integer>sayHello(123);
Обидва дають однакові результати.
Hello Bob
Hello 123