Pull to refresh

Comments 32

public class FloatList extends ArrayList{}

наверно стоит заменить на
public class FloatList extends ArrayList{};

правильно?
Скорее на
public class FloatList extends ArrayList<Float> {}
Да, верно. Потерялось в процессе «раскрашивания кода».
ыы
именно это и хотел сказать.

любимый Хабр зачем-то покрошил [Float], видимо как html-тэг.
А зачем это понадобилось? Если не секрет?
Пример ситуации: в слое представления есть формы с таблицами. Столбцы в таблицах — соотносятся с полями некоторых сущностей в модели данных (в одной таблице могут присутствовать поля из разных связанных сущностей). Задача: организовать фильтрацию и сортировку по столбцам таблиц средствами базы данных. То есть нужно преобразовать информацию о том, какие столбцы таблицы выбраны для фильтрации/сортировки в информацию о полях сущностей, потом по этой информации построить Criteria для выборки данных, получить данные и развернуть цепочку в обратном направлении. Вот для всего этого на некоторых этапах понадобилась возможность анализировать параметры (хотя есть обходные пути).
например, для написания Generic DAO.
В Hibernate / Seam так делают

вполне удобно
Думаю Автор бывший .NET-чик, потому что в .NET-е Generic-и работают на runtime-е.

В 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}
}
По-хорошему — так и нужно делать. То есть передавать в конструктор реальный класс, а не искать его так как описано в топике. Это просто, надёжно и полностью корректно.

Но иногда — это не очень удобно: довешивать в конструкторы дополнительный параметр. Особенно — если классов сотни, а ты можешь гарантировать, что все они будут параметризованы при наследовании. Собственно это и стало причиной топика.
это понятно — не всегда получалось красиво — помогала либо строгая иерархия классов (чтобы по имени вытащить генерализацию), либо аннотирование. Попробуем применить в жизни — как знать, может, пригодится :)
Хотелось бы уточнить ещё одну вещь.
Чёрт, комментарий отправился раньше, чем нужно.
Так вот
    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
Поясните, чем она аналогична? Не наблюдаю в ней решения проблемы, описанной в топике. Если вы про метод getSuperclassTypeParameter(...), то он представляет собой как раз то, от чего я отказался в начале статьи по причине ограниченности применения.
Проблема описанная в топике: определить класс, которым параметризован generic-класс. В простом случае подходит. Аналогичный не значит лучший.
Простите, но решение в виде
type.getActualTypeArguments()[0]
* отправилось раньше времени.

Простите, но решение в виде:
type.getActualTypeArguments()[0]
используемое в приведенном коде от гугла 1 в 1 присутствует в статье. И не решает основную задачу в полном объеме. А этот тривиальный случай с одним параметром находится поиском того же Гугла на сотне сайтов.

В итоге всё еще не понятна цель вашего первого комментария.
повесить закладку на сорц, чтобы просто было найти при необходимости
Хотите повесить на что-то закладку — вешайте. Но для этого вовсе не обязательно засорять топики на Хабре.
релевантность налицо. имхо, дискуссия неконструктивна
Релевантность? Конечно информация релевантна сама себе. Но в данном случае от повторения информации нет никакого толку. Вы добавили в топик то же самое, что уже было в нем описано.

Насчет неконструктивности — согласен :)
Sign up to leave a comment.

Articles