Во время навигации по классу java.lang.reflect.Method я наткнулся на метод isBridge. Его Javadoc говорит, что он возвращает true, только если спецификация Java объявляет метод как true.
Пожалуйста, помогите мне понять, для чего это используется! Может ли пользовательский класс объявить свой метод как мост, если это необходимо?




Компилятор может создать метод моста при расширении параметризованного типа, методы которого имеют параметризованные аргументы.
В этом классе МостМетодРезольвер вы можете найти способ получить реальный метод, на который ссылается «метод моста».
См. Создание кадра, синхронизация, управление передачей:
В качестве примера такой ситуации рассмотрим объявления:
class C<T> { abstract T id(T x); }
class D extends C<String> { String id(String x) { return x; } }
Теперь, учитывая призыв
C c = new D();
c.id(new Object()); // fails with a ClassCastException
Стирание фактического вызываемого метода, D.id(String) отличается по своей сигнатуре от сигнатуры объявления метода времени компиляции, C.id(Object). Первый принимает аргумент типа String, а второй - аргумент типа Object. Вызов завершается с ошибкой ClassCastException до выполнения тела метода.
Такие ситуации могут возникнуть только в том случае, если программа выдает непроверенное предупреждение (§5.1.9).
Реализации могут обеспечить соблюдение этой семантики, создав методы моста. В приведенном выше примере в классе D будет создан следующий метод моста:
Object id(Object x) { return id((String) x); }
Это метод, который на самом деле будет вызываться виртуальной машиной Java в ответ на вызов c.id(new Object()), показанный выше, и он выполнит приведение и завершится неудачно, если потребуется.
См. Также Мост:
как упоминалось в комментарии, методы моста также необходимы для ковариантное преобладание:
Как правило, метод Object clone() можно переопределить с помощью MyObject clone(), но метод моста будет сгенерирован компилятором:
public bridge Object MyObject.clone();
@BrunoJCM хороший улов. Восстановил ссылку (класс перенесен из проекта org.springframework.core в проект spring-framework: fisheye.springsource.org/browse/spring-framework/…)
Третье использование методов моста - это изменение видимости методов для публичных, если класс был объявлен с приватной видимостью пакета.
Показанный там пример (цитируемый из 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, если не создан метод моста. Метод моста позволяет всему типизированному коду использовать эту реализацию 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");
Другой случай, на который я наткнулся, не имеет ничего общего с дженериками:
protected abstract class Super {
public void m() {}
}
public class Sub extends Super {}
assert Sub.class.getMethod("m").isBridge();
Даже без дженериков методы моста необходимы для ковариантных возвращаемых типов.