Для чего используется Method.isBridge?

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

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

Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
27
0
5 512
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ответ принят как подходящий

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

В этом классе МостМетодРезольвер вы можете найти способ получить реальный метод, на который ссылается «метод моста».

См. Создание кадра, синхронизация, управление передачей:

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

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

См. Также Мост:

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

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

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

public bridge Object MyObject.clone();

Даже без дженериков методы моста необходимы для ковариантных возвращаемых типов.

Tom Hawtin - tackline 14.11.2008 14:51

@BrunoJCM хороший улов. Восстановил ссылку (класс перенесен из проекта org.springframework.core в проект spring-framework: fisheye.springsource.org/browse/spring-framework/…)

VonC 16.11.2012 10:30

Третье использование методов моста - это изменение видимости методов для публичных, если класс был объявлен с приватной видимостью пакета.

Rafael Winterhalter 21.04.2014 01:58

Показанный там пример (цитируемый из 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();

Другие вопросы по теме