Автозаполнение Eclipse - как оно узнает о дженериках, когда доступен только двоичный файл jar? - PullRequest
11 голосов
/ 20 февраля 2011

Обобщения Java реализованы с использованием стирания типов.Это означает, что если у меня есть метод:

public void setMapParam(Map<String, Integer> p) { ... }

после компиляции, он окажется в .class как:

public void setMapParam(Map p) { ... }

У меня есть JAR-файл с общими классами и методамикак и выше.Это просто двоичный файл.Нет исходного кода, нет ничего.

Но когда я использую его в коде, автозаполнение Eclipse дает мне setMapParam(Map<String, Integer> p), хотя в двоичном коде это похоже на setMapParam(Map p).

Как теперь Eclipse имеет тип (Map<String, Integer>)даже если сигнатура метода была стерта (до Map)?Или я что-то упустил?

Ответы [ 2 ]

17 голосов
/ 20 февраля 2011

Стирание типа не означает, что скомпилированный код не содержит информации о параметрах типа. Параметры типа, используемые в определениях классов и членов, присутствуют в скомпилированном коде и доступны посредством отражения (см. TypeVariable).

Что означает стирание типа, так это то, что у объекта экземпляры нет индивидуальных параметров типа. Учитывая определение класса MapImpl extends HashMap<T extends Comparable, Integer> и экземпляр этого класса, вы не можете узнать, какое конкретное значение T было использовано в коде, который создал экземпляр, потому что эта информация не существует. Но вы можете узнать, что это extends Comparable и что тип значения - Integer, потому что эта информация является частью определения класса (и используется всеми экземплярами).

7 голосов
/ 20 февраля 2011

Нет, параметры сохраняют информацию общего типа.

Стирание типа - это, например, экземпляр List<T>, который не знает, что такое T во время выполнения. Есть только класс List - остальное зависит от компилятора. Но компилятор может использовать информацию о типах параметров и сам тип.

Вот пример:

import java.util.*;
import java.lang.reflect.*;

public class Test {

    public void foo(List<String> list) {
    }

    public static void main(String[] args) throws Exception{
        Method method = Test.class.getMethod("foo", List.class);
        Type parameterType = method.getGenericParameterTypes()[0];
        System.out.println(parameterType);
    }
}

Это распечатывает:

java.util.List<java.lang.String>

Так что информация о типе была сохранена в метаданных для метода.

...