Комментарии 32
Полезно, благодарен
public class FloatList extends ArrayList{}
наверно стоит заменить на
public class FloatList extends ArrayList{};
правильно?
наверно стоит заменить на
public class FloatList extends ArrayList{};
правильно?
А зачем это понадобилось? Если не секрет?
Пример ситуации: в слое представления есть формы с таблицами. Столбцы в таблицах — соотносятся с полями некоторых сущностей в модели данных (в одной таблице могут присутствовать поля из разных связанных сущностей). Задача: организовать фильтрацию и сортировку по столбцам таблиц средствами базы данных. То есть нужно преобразовать информацию о том, какие столбцы таблицы выбраны для фильтрации/сортировки в информацию о полях сущностей, потом по этой информации построить Criteria для выборки данных, получить данные и развернуть цепочку в обратном направлении. Вот для всего этого на некоторых этапах понадобилась возможность анализировать параметры (хотя есть обходные пути).
например, для написания Generic DAO.
В Hibernate / Seam так делают
вполне удобно
В Hibernate / Seam так делают
вполне удобно
Думаю Автор бывший .NET-чик, потому что в .NET-е Generic-и работают на runtime-е.
В JAVA изза обратной совместимости Generic — и работают только в compile time, в отличие от .NET-а, в котором существует две копии библиотек колекций: с generic-ами и без.
На JAVA такого рода задачи лучше решать.
Хочу также обратить внимание на парамертрезированый тип Class метода getXType, так как это являеться хороши тоном в JAVA.
Это также являеться хорошим примером Strong Typed программировния, потому что конструкция abstract/Class всегда будет следить за тем что getXType возвращает именно тот тип который указан в качестве generic-а.
В JAVA изза обратной совместимости Generic — и работают только в compile time, в отличие от .NET-а, в котором существует две копии библиотек колекций: с generic-ами и без.
На JAVA такого рода задачи лучше решать.
abstract class Base<X>{
public abstract Class<X> getXType();
}
class MyClass extends Base<String>{
public Class<String> getXType(){
return String.class;
}
}
Хочу также обратить внимание на парамертрезированый тип Class метода getXType, так как это являеться хороши тоном в JAVA.
Это также являеться хорошим примером Strong Typed программировния, потому что конструкция abstract/Class всегда будет следить за тем что getXType возвращает именно тот тип который указан в качестве generic-а.
К сожалению этот метод применим только в ситуации, когда есть возможность менять код тех классов, для которых нужно определить тип. Если нужно получить информацию о параметризованном классе, опреденном в стороннем коде, то всё же понадобится метод вроде того, что в топике.
Вы догадываетесь, что будет, если в иерархии классов встретится непараметризуемый/непараметризованный класс?
Например:
Например:
public class Test { private class A<T> {} private class B extends A<String> {} private class C<T> extends B {} private class D extends C<Object> {} public static void main(String[] args) throws Exception { Class<?> clazz = C.class; System.out.println(clazz.getGenericSuperclass() instanceof ParameterizedType); ReflectionUtils.getGenericParameterClass(D.class, A.class, 0); // ClassCastException, а должно было вернуть String.class } }
Полезно! Если честно, то даже не задумывался о попытке вытfщить класс генерика, применял конструкции типа
class Test{
Classt;
public Test(Classgen){t = gen}
}
class Test{
Classt;
public Test(Classgen){t = gen}
}
По-хорошему — так и нужно делать. То есть передавать в конструктор реальный класс, а не искать его так как описано в топике. Это просто, надёжно и полностью корректно.
Но иногда — это не очень удобно: довешивать в конструкторы дополнительный параметр. Особенно — если классов сотни, а ты можешь гарантировать, что все они будут параметризованы при наследовании. Собственно это и стало причиной топика.
Но иногда — это не очень удобно: довешивать в конструкторы дополнительный параметр. Особенно — если классов сотни, а ты можешь гарантировать, что все они будут параметризованы при наследовании. Собственно это и стало причиной топика.
Хотелось бы уточнить ещё одну вещь.
Чёрт, комментарий отправился раньше, чем нужно.
Так вот
Вообще говоря, массив, примитивный тип и интерфейс являются классами (см. Class#isArray(), Class#isPrimitive(), Class#isInterface(); если точнее, то примитивы — не классы, но для них есть соответствующие классы).
Правда, если параметризовать класс-родитель массивом, то параметр действительно вернётся не как Class, а как GenericArrayType — и это единственный возможный случай попасть в этот блок кода. Потому что примитивным типом вообще нельзя параметризовать класс-родитель.
Ещё один наследник (кроме, собственно, GenericArrayType, ParameterizedType, TypeVariable и Class) интерфейса Type — WildcardType (представляющий wildcard'ы) — и им тоже, как и примитивом, нельзя параметризовать класс-родитель при наследовании.
Так вот
if (!(result instanceof Class)) { // Похоже, что параметр - массив, примитивный типи, интерфейс или еще-что-то, что не является классом. throw new IllegalStateException("Actual parameter type for " + actualClass.getName() + " is not a Class."); }
Вообще говоря, массив, примитивный тип и интерфейс являются классами (см. Class#isArray(), Class#isPrimitive(), Class#isInterface(); если точнее, то примитивы — не классы, но для них есть соответствующие классы).
Правда, если параметризовать класс-родитель массивом, то параметр действительно вернётся не как Class, а как GenericArrayType — и это единственный возможный случай попасть в этот блок кода. Потому что примитивным типом вообще нельзя параметризовать класс-родитель.
Ещё один наследник (кроме, собственно, GenericArrayType, ParameterizedType, TypeVariable и Class) интерфейса Type — WildcardType (представляющий wildcard'ы) — и им тоже, как и примитивом, нельзя параметризовать класс-родитель при наследовании.
Уточнение к «примитивным типом вообще нельзя параметризовать класс-родитель»: примитивным типом нельзя вообще ничего параметризовать, в том числе и класс-родитель :) А вот массивом примитивных типов (например,
int[]
) — можно.Да, верно — этот комментарий был не корректен. Действительно, попасть в данный блок кода можно только параметризовав класс массивом (неважно каким): примитивным классом параметризовать класс нельзя, а с интерфейсами проблемы нет — основная ветка кода с ними прекрасно справляется. В частности у меня в примере иерархии встречается интерфейс Set, который обрабатывается без проблем.
Поправил комментарий в коде.
Поправил комментарий в коде.
А тесты для ReflectionUtils есть?
Мне как раз такое понадобилось, но без тестов использовать страшно. ;-)
Мне как раз такое понадобилось, но без тестов использовать страшно. ;-)
Аналогичная реализация от гугла:
code.google.com/p/google-gson/source/browse/trunk/gson/src/main/java/com/google/gson/reflect/TypeToken.java
code.google.com/p/google-gson/source/browse/trunk/gson/src/main/java/com/google/gson/reflect/TypeToken.java
Поясните, чем она аналогична? Не наблюдаю в ней решения проблемы, описанной в топике. Если вы про метод getSuperclassTypeParameter(...), то он представляет собой как раз то, от чего я отказался в начале статьи по причине ограниченности применения.
Проблема описанная в топике: определить класс, которым параметризован generic-класс. В простом случае подходит. Аналогичный не значит лучший.
Простите, но решение в виде
type.getActualTypeArguments()[0]
* отправилось раньше времени.
Простите, но решение в виде:
В итоге всё еще не понятна цель вашего первого комментария.
Простите, но решение в виде:
type.getActualTypeArguments()[0]используемое в приведенном коде от гугла 1 в 1 присутствует в статье. И не решает основную задачу в полном объеме. А этот тривиальный случай с одним параметром находится поиском того же Гугла на сотне сайтов.
В итоге всё еще не понятна цель вашего первого комментария.
Зарегистрируйтесь на Хабре, чтобы оставить комментарий
Узнаем параметр Generic-класса в Java