2016-03-15 3 views
0

При переходе через некоторые блоги Jakov Jenkov на Java Reflection и дженериков, я нашел следующий пункт:Java дженериков и отражения (jenkov блог)

Когда во время выполнения проверки самого параметрируемого типа, как java.util.List, нет способ узнать, какой тип был параметризован. Это имеет смысл, поскольку тип может быть параметризован для всех типов типов в одном приложении. Но, когда вы проверяете метод или поле, объявляющее использование параметризованного типа, во время выполнения вы можете увидеть, к какому типу параметризуемый тип был параметризован.

Может ли кто-нибудь прокомментировать абзац?

Я запуталась в заявлении «когда во время выполнения проверяющего сам параметрируемого типа»

ответ

3

Рассмотрим следующую небольшую программу:

import java.util.ArrayList; 

class MyClass { 
    ArrayList<String> stringList; 

    public ArrayList<String> getStringList() { 
     return stringList; 
    } 
} 

public class Foo { 
    public static void main(String... args) throws NoSuchMethodException { 
     ArrayList<Integer> intList = new ArrayList<>(); 
     System.out.println(intList.getClass().toGenericString()); 
     System.out.println(MyClass.class.getMethod("getStringList").toGenericString()); 
    } 
} 

Выходной сигнал этой программы:

public class java.util.ArrayList<E> 
public java.util.ArrayList<java.lang.String> MyClass.getStringList() 

Как вы видите, тот факт, что intList является ArrayList<Integer> не известно, во время выполнения, но тот факт, что MyClass.getStringList() возвращает ArrayList<String> есть.

Причина заключается в том, что все экземпляры ArrayList (некоторые из которых могут быть ArrayList<Integer> ы и другие ArrayList<String> ы) разделяют один и тот же объект Class:

ArrayList<String> stringList = new ArrayList<>(); 
ArrayList<Integer> intList = new ArrayList<>(); 
System.out.println(stringList.getClass() == intList.getClass()); 

будет выводить true. Так что intList.getClass() ничего не знает о параметрах типа объекта.

С другой стороны, объект, возвращаемый MyClass.getStringList(), всегда является строковым списком, и эту информацию можно увидеть во время выполнения.

0

дженериков в Java это время компиляции вещь. Нет способов получить какую-либо информацию о типах дженериков во время выполнения, но нулевые объекты содержат информацию об их типах.

Так что, если у вас есть метод, который принимает List<T> и список не пуст, вы можете сделать что-то подобное:

if (list.get(0) instanceOf X) { // ... }

Если вы читали некоторые Java-код с дженериков, вы» Л.Л. нашли много способов, как, что:

<T> T getSomething(Class<T> aClass); 

причина, почему какой-то объект, несущий тип требуется, является то, что не существует такого понятия, как родовые типы в режиме исполнения на всех.

+0

Некоторая общая информация доступна там, где компилятор должен будет проверить этот код, например. поле, параметры метода, тип возвращаемого метода, суперклассы и интерфейсы. Он недоступен через объект, если это не косвенно через одно из указанных средств. –

+1

@PeterLawrey Возможно, вы правы, но часто трудно понять границы применимости этих вещей. Вы имели в виду что-то вроде этого? http://stackoverflow.com/a/3403976/1240328 –

+0

Да, информация в коде доступна через отражение. Однако в экземпляре нет дополнительной информации. –

0

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

1

Считайте, что у вас есть следующий класс:

public class ReflectionTest { 
    List<Integer> list1 = new ArrayList<>(); 
    List<String> list2 = new ArrayList<>(); 
} 

инспектирующих параметризированный типа само по себе означает проверки list1.getClass() или list2.getClass(). Они абсолютно неотличимы:

System.out.println(list1.getClass() == list2.getClass()); 
// prints true 

Все экземпляры ArrayList являются экземплярами одного и того же класса, независимо от параметризации, так что наличие только list1.getClass() или list2.getClass() у вас нет никакого способа, чтобы определить, был ли он параметризованных с Integer или String.

Однако, если у вас есть прямой доступ к полю, вы можете это сделать:

System.out.println(ReflectionTest.class.getDeclaredField("list1").getGenericType()); 
// prints java.util.List<java.lang.Integer> 
System.out.println(ReflectionTest.class.getDeclaredField("list2").getGenericType()); 
// prints java.util.List<java.lang.String> 

Потому что здесь вы подключаетесь поле себя и текущая параметризация хранится в файле класса вместе с декларацией поля.То же самое можно проверить, если вы проверяете параметр метода или возвращаемое значение: фактическая общая подпись также сохраняется в файле класса вместе с удаленной подписью.

Смежные вопросы