Показанный там пример (цитируемый из JLS) звучит так, будто методы моста используются только в ситуациях, когда используются необработанные типы. Поскольку это не так, я подумал, что приведу пример, в котором методы моста используются для полностью корректного типа универсального кода.
Рассмотрим следующий интерфейс и функцию:
public static interface Function<A,R> {
public R apply (A arg);
}
public static <A, R> R applyFunc (Function<A,R> func, A arg) {
return func.apply(arg);
}
Если вы используете этот код следующим образом, используется метод моста:
Function<String, String> lower = new Function<String, String>() {
public String apply (String arg) {
return arg.toLowerCase();
}
};
applyFunc(lower, "Hello");
После удаления интерфейс Function
содержит метод apply(Object)Object
(который можно подтвердить, декомпилировав байт-код). Естественно, если вы посмотрите на декомпилированный код для applyFunc
, вы увидите, что он содержит вызов apply(Object)Object
. Object
является верхней границей переменных типа, поэтому никакая другая сигнатура не будет иметь смысла.
Таким образом, когда анонимный класс создается с помощью метода apply(String)String
, он фактически не реализует интерфейс Function
, если не создан метод моста. Метод bridge позволяет всему типизированному коду использовать эту реализацию Function
.
Интересно, что только если класс реализует какой-либо другой интерфейс с сигнатурой apply(String)String
и только если метод вызывается через ссылку этого типа интерфейса, компилятор когда-либо будет генерировать вызов с этой сигнатурой.
Даже если у меня есть следующий код:
Function<String, String> lower = ...;
lower.apply("Hello");
Компилятор по-прежнему отправляет вызов apply(Object)Object
.
На самом деле есть еще один способ заставить компилятор вызывать apply(String)String
, но он использует магический тип, присваиваемый анонимному выражению создания класса, который иначе не может быть записан:
new Function<String, String>() {
public String apply (String arg) {
return arg.toLowerCase();
}
}.apply("Hello");