Как java erasure решил, какой бросок сделать, чтобы вернуть тип? - PullRequest
0 голосов
/ 22 октября 2019

Я трачу много времени на изучение общей функции в Java. Я попытался прочитать объяснение по следующей ссылке: https://docs.oracle.com/javase/tutorial/java/generics/bridgeMethods.html, и я не понял, а также попытался понять проблему по следующей ссылке на форуме: Стирание типа Java: правила вставки приведений? , но мне все еще далеко до ясности, и я также добавил комментарий к сообщению, но я сомневаюсь, что кто-то будет ссылаться на комментарий, потому что сообщение очень старое.

Я пытаюсь понять, как компилятор знает, какое приведение сделать для метода, возвращаемого типа, когда он делает стирание. В книге, из которой я учусь (Deital - Java Как программировать), я думаю, что что-то в объяснении отсутствует (возможно, опечатка). Там написано: «В каждом случае тип приведения для возвращаемого значения выводится из типов аргументов метода в конкретном вызове метода, потому что, согласно объявлению метода, тип возвращаемого значения и типы аргументов совпадаютКак я понимаю, предложение говорит, что приведение выполняется в соответствии с аргументами, которые были отправлены при вызове метода. Но если методы не получают аргументов, например, если прототип метода:

public static <T extends Animal> T funcA ()

Теперь функцию вызывают 3 различных метода: один хочет получить Dog возвращаемого типа (Dog d = funcA()), второй хочет получить Cat (Cat c = funcA()), а последний хочет получить Animal (* 1012). *). Как Erasure решает, какой актерский состав сделать?

Ответы [ 4 ]

2 голосов
/ 22 октября 2019

Это на самом деле не имеет ничего общего с стиранием. Тип выведен из сайта вызова : какой тип "фактически ожидает вызывающий абонент". Animal a = funcA() эквивалентно Animal a = MyClass.<Animal>funcA(), Dog d = funcA() эквивалентно Dog d = MyClass.<Dog>funcA().

Работает ли это на уровне реализации , действительно имеет отношение к стиранию, и на самом деле не существует действительной реализации для funcA - той, которая не будет иметь предупреждений компилятора, или, что эквивалентно, той, котораяне потерпит неудачу во время выполнения - кроме (что-то, что сводится к) return null.

0 голосов
/ 22 октября 2019

Имеется 3 различных проблемы:

  • Стирание типа фактического метода

  • Мостовые методы при переопределении унаследованного метода

  • Приведение при вызове метода


Ваш пример:

public static <T extends Animal> T funcA ()

Этот метод не может иметь ничего общего сметоды моста, потому что он статический.

Стирание типа означает, что компилятор исключает (стирает) универсальный тип, поэтому код компилируется так, как будто вы написали:

public static Animal funcA ()

Из-зачто, когда вы затем вызываете метод, приведение добавляется компилятором:

Dog d = (Dog) funcA()

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


Теперь, если вы на самом деле интересовались мостовыми методами и тем, как работает стирание, давайте посмотрим на пример в ссылке , которую вы предоставили.

В этой статье метод в базовых классахs объявлен как:

public class Node<T> {
    public void setData(T data)

Erasure компилирует это как:

public class Node {
    public void setData(Object data)

В подклассе метод объявлен как:

public class MyNode extends Node<Integer> {
    public void setData(Integer data)

Erasure компилирует это как:

public class MyNode extends Node {
    public void setData(Integer data)

Теперь компилятор добавляет метод моста, поскольку JVM требуется метод переопределения в подклассе с типом параметра Object:

@Override
public void setData(Object data) {
    setData((Integer) data);
}

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

0 голосов
/ 22 октября 2019

на основе типов целей в следующих выражениях

  • Dog d = funcA ()

  • Cat c = funcA ()

  • Animal A = funcA ()

компилятор использует вывод типа (https://docs.oracle.com/javase/tutorial/java/generics/genTypeInference.html). Если вы посмотрите на примеры в TargetВ разделе «Типы» вы увидите нечто похожее на то, что вы просите.

0 голосов
/ 22 октября 2019

В общем коде нет приведения. В Java ссылки на объекты являются двоичными без изменений при вычислении выражения приведения. Любой тип ссылки всегда просто object. Все остальное - гарантии от компилятора. Поэтому нет необходимости в приведении в общем коде.

На самом деле приведение генерирует только некоторый код, такой как

if (!(obj instanceof desiredtype))
    throw new ClassCastException();

Однако Java позволяет приводить из нетипизированных типов к универсальным типам. Это может привести к неправильным типам, возвращаемым функциями. Это зависит от звонящего, чтобы справиться с этой ситуацией. Три звонящих знают свой индивидуальный, ожидаемый тип. Таким образом, они могут при необходимости проверить неожиданные результаты (например, приведение).

...