Подтвердить что ты не робот

Какой java.lang.reflect.Method.isBridge() используется?

Во время навигации класса Method я столкнулся с функцией isBridge(), javadoc которой говорит, что ее true, только если спецификация java объявляет метод как истинный.

Пожалуйста, помогите мне понять, для чего это используется? Может ли пользовательский класс объявлять свой метод как мост, если требуется?

4b9b3361

Ответ 1

Мощный метод может быть создан компилятором при расширении параметризованного типа, методы которого имеют параметризованные аргументы.

Вы можете найти в этом классе BridgeMethodResolver способ получить фактический метод, упомянутый "мостовым методом".

См. Создать фрейм, Синхронизировать, Управление передачей:

В качестве примера такой ситуации рассмотрим объявления:

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()), показанный выше, и он выполнит приведение и завершение работы, если требуется.

См. также Bridge:

как указано в комментарии, мостовые методы также необходимы для ковариантного переопределения:

  • В Java 1.4 и ранее один метод может переопределить другой, если соответствие подписи точно.
  • В Java 5 метод может переопределить другой, если аргументы соответствуют точно, но тип возвращаемого метода переопределения, если он является подтипом возвращаемого типа другого метода.

Как правило, метод Object clone() можно переопределить с помощью MyObject clone(), но компилятор будет генерировать мостиковый метод:

public bridge Object MyObject.clone();

Ответ 2

Пример, показанный там (цитируемый из JLS), заставляет его звучать как мостовые методы, которые используются только в ситуациях, когда используются типы raw. Так как это не так, я думал, что подключусь к примеру, когда методы моста используются для полностью типичного кода с полным кодом.

Рассмотрим следующий интерфейс и функцию:

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");

Ответ 3

Другой случай, который я наткнулся, не имеет ничего общего с дженериками:

protected abstract class Super {
    public void m() {}
}
public class Sub extends Super {}
assert Sub.class.getMethod("m").isBridge();