Генерация синтетического метода интерфейса Java при сужении типа возвращаемого значения - PullRequest
2 голосов
/ 23 сентября 2019

У меня есть 2 интерфейса и 2 типа возврата.

interface interfaceA {
   Publisher<String> doSomething();
}

interface interfaceB extends interfaceA {
   Flow<String> doSomething();
}

interface Publisher<T>{}
class Flow<T> implements Publisher<T>{}

Итак, во время выполнения я вижу 2 метода: interfaceB.class.getMethods()

  1. public default my.package.Publisher my.package.interfaceB.doSomething()

  2. public abstract my.package.Flow my.package.interfaceB.doSomething()

Что касается первого, то оно синтетическое.(method.getModifiers() & 0x00001000 > 0) == true

Генерирует ли Java этот синтетический метод?

Как это работает в целом?

Ответы [ 2 ]

2 голосов
/ 23 сентября 2019

То, что вы видите здесь, называется методом моста.

Чтобы понять, зачем это нужно, мы должны посмотреть, как JVM определяет, отличаются ли два метода:

  • У каждого метода есть имя.Другое имя -> другой метод.
  • У каждого метода есть дескриптор.Другой дескриптор-> другой метод.

Дескриптор содержит все аргументы и тип возвращаемого значения (с обобщениями это стирание).

С точки зрения JVM Flow doSomething() - это другой методчем Publisher doSomething(), поэтому, когда его просят сделать вызов invokeinterface для Publisher doSomething(), он не будет вызывать Flow doSomething().

Это может произойти, если цель на месте вызова имеет тип interfaceA:

intefaceA foo = ...;
foo.doSomething();

Но с точки зрения языка оба метода одинаковы, и один переопределяет другой.

Чтобы восстановить это отношение, javac добавляет метод моста с исходным типом метода.это просто вызывает перегруженный метод.

0 голосов
/ 23 сентября 2019

Спецификация языка Java определяет следующее:

Конструкция, генерируемая компилятором Java, должна быть помечена как синтетическая, если она не соответствует конструкции, объявленной явно или неявнов исходном коде, если только испускаемая конструкция не является методом инициализации класса

Другое определение, которое я видел из Документы Java :

Когдавключающий класс обращается к закрытому атрибуту вложенного класса, компилятор Java создает синтетический метод для этого атрибута.

РЕДАКТИРОВАТЬ: Было отмечено, что некоторые из положений этой статьи относятся к более старой версии Java (SE7), поэтому будьте внимательны при чтении онлайн-статей.

Так, например:

import static java.lang.System.out;

public class Synthetic {

  public static void main(String[] arguments) {
      Synthetic.NestedClass nested = new Synthetic.NestedClass();
      out.println("Age: " + nested.age);
  }

  private static final class NestedClass {

      private String myName = "Tom";

      private int age = 42;

  }

}

Компилятор создает синтетические методы для каждого частного атрибута, к которому осуществляется доступ.Таким образом, он создаст синтетический метод (static int access$000(Synthetic$NestedClass)) для age, но не myName

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...