![]() |
Модераторы: LSD, AntonSaburov |
![]() ![]() ![]() |
|
HugeX |
|
|||
Новичок Профиль Группа: Участник Сообщений: 35 Регистрация: 19.9.2009 Репутация: нет Всего: нет |
Добрый день всем.
Я при помощи рефлексии загружаю класс, который наследует интерфейс и создаю объект. Подскажите, пожалуйста, как преобразовать объект этого класса в объект интерфейса. |
|||
|
||||
AntonSaburov |
|
|||
![]() Штурман ![]() ![]() ![]() ![]() Профиль Группа: Модератор Сообщений: 5658 Регистрация: 2.7.2002 Где: Санкт-Петербург Репутация: 51 Всего: 118 |
Странная фраза - если класс реализует интерфейс, то объект этого класса реализует интерфейс. И к нему можно обращаться как к интерфейсом. Не понятна проблема.
|
|||
|
||||
powerOn |
|
|||
![]() software saboteur ![]() ![]() ![]() ![]() Профиль Группа: Участник Сообщений: 4367 Регистрация: 7.10.2005 Репутация: 47 Всего: 159 |
Тоже не особо понял что имеется ввиду. Может downcasting нужен?
|
|||
|
||||
priam220 |
|
|||
![]() Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 291 Регистрация: 4.6.2010 Репутация: 7 Всего: 8 |
не совсем понимаю зачем рефлексия нужна в Java. Прочитал статью на оракловом портале. Куча примеров, заканчивается и начинается тем, что это вот такая фича, которой нет не в С не в Паскале, но так и не понял, что этот подход дает. Видел в проектах применение рефлексии, но везде можно было бы обойтись и без нее. Кое где попадается фразы, что это ускоряет процесс обработки кода. Местами - обратное.
Хотелось бы узнать, что дает рефлексия в Java , без чего нельзя жить. Рефлексивный код, скажем сравнения классов, выглядит как то чуждо на фоне остального объектного кода, но все же его пишут. |
|||
|
||||
Skipy |
|
|||
![]() Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 487 Регистрация: 24.8.2006 Где: Москва, Россия Репутация: 6 Всего: 16 |
Если бы без нее нельзя было жить - использовали бы повсеместно. Рефлексия нужна там, где она нужна. И местами она оказывается не просто полезной, а до безобразия полезной. Например, есть у Вас интерфейс, методы которого надо вызывать в GUI-потоке. Стандартный вариант - вокруг метода написать обертку с SwingUtilities.invokeLater. Громоздко, за обертками кода не видно. Вариант рефлексии - создать динамический прокси, который будет перехватывать вызовы и везде, где надо, добавлять обертку. Тогда в реализации интерфейса можно обойтись просто аннотациями - @CallInGUIThread. Код чистый и понятный. Это первое, что на ум пришло. А если начну думать - до ночи писать буду. У нас в текущем проекте на рефлексии очень много чего построено. Это сообщение отредактировал(а) Skipy - 11.11.2010, 12:05 |
|||
|
||||
priam220 |
|
|||
![]() Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 291 Регистрация: 4.6.2010 Репутация: 7 Всего: 8 |
Skipy, спасибо что ответил, но прошу понять меня правильно, - далеко не все крутые джависты работали со свингом, а не крутые и в смятку, - подавно. Хотелось бы простой пример, на котором бы стало понятно, что вот мол да, без рефлексии - никуда. Или чем лучше newInctance от простого new(). Вот например сетается форма из бина, свинговая, кстати:
this.setTitle(visualBean.getClass().getAnnotation(VisualBean.class).value()); Неужели все только для того, что бы сеттеры убрать? А чем хуже так: this.setTitle(vb.getTitle); Думаю все согласятся, что вторая строчка куда понятнее, нагляднее и проще. А когда таких строк с 3-4 десятка? ![]() Это сообщение отредактировал(а) priam220 - 12.11.2010, 01:04 |
|||
|
||||
mantracoder |
|
|||
Шустрый ![]() Профиль Группа: Участник Сообщений: 51 Регистрация: 3.8.2007 Репутация: 1 Всего: 1 |
Возьмем другой пример - Hibernate, облегчающий жизнь при работе с БД. Задача Hibernate - сохранять / извлекать пользовательские объекты из реляционной базы данных. Программисту необходимо сделать мэппинг (будь то аннотации или XML-документ(ы)), описывающий соответствие полей объекта полям таблицы, взаимосвязи объектов и т.д. Для программиста существуют бизнес-объекты типа Customer, Order, Invoice. Hibernate абстрагирован от пользовательской логики - для него любой мой бизнес-объект - просто Object, а мэппинг - инструкция, какие именно свойства этого объекта каким полям таблицы соответствуют. Если Hibernate полностью отвязан от логики моего приложения, то его единственным доступом к значениям, которые хранятся в моих объектах, является рефлексия. В большинстве случаев рефлексию целесообразно использовать там, где необходимо максимально абстрагироваться от самой точки приложения этого полезного инструмента. |
|||
|
||||
Skipy |
|
||||||||||
![]() Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 487 Регистрация: 24.8.2006 Где: Москва, Россия Репутация: 6 Всего: 16 |
Я еще раз говорю - "никуда" бывает крайне редко. Чаще бывает "можно, но намного сложнее". Например. У Вас объект вызывает некий интерфейс, через который получает данные. Это интерфейс, вернее, его реализация, смотрит на пул сервисов. Берет оттуда произвольный и вызывает. А сервисы имеют тенденцию периодически отваливаться. Соответственно, надо обеспечить устойчивость вызова. Вариант "в лоб". При каждом вызове в клиентском коде ловить исключение, брать другой сервис и вызывать опять. Вызовов по коду - десятки тысяч, реализаций интерфейса, которые надо так обрабатывать - сотни. Масштабы обработки представляете? Вариант через рефлексию. Вместо реализации интерфейса Вы используете динамический прокси. Получаете Вы его из той же точки, откуда и обычную реализацию, так что клиентский код разницы не видит. Обработчик перехватывает исключение и производит повторный вызов другого сервиса из пула. Клиентский код этого тоже не видит - он вызвал метод и получил результат. Для всех реализаций и во всех точках вызова. Еще пример - обработчик исключений верхнего уровня. Те, которые долетели до самого верха, надо обработать. Пишете методы типа handleCOMM_FAILURE, handleTRANSIENT, handleExSystem - для тех исключений, которые хотите обработать. Дальше, в catch берете имя класса пойманного исключения, приписываете handle и ищете в обработчике метод с таким именем. Нашли - вызываете. Чем это лучше бесконечных проверок instanceof? Тем, что Вы можете написать свой обработчик исключений, просто передать в этот механизм и получить обработку всех нужных Вам исключений без изменения механизма, только его расширением. Еще пример - ниже.
У Вас класс, параметризованный.
Вам нужно создавать экземпляр по типу параметризации. new T() Вам сделать никто не даст - в runtime типа у Вас нет. А вот если Вы туда передадите при содании Class<T>, то сделать clazz.newInstance() получится:
И НИКАК иначе Вы экземпляр по типу параметризации не создадите. Вот тут уже действительно без рефлексии никуда.
Это не самый хороший пример, но тем не менее. Чем это лучше? Могу предположить, тем, что у бина во втором случае обязательно должен быть метод getTitle. Если он нужен только для отображения заголовка формы - такого метода быть не должно, он не относится к бизнес-логике бина. Это некая вспомогательная информация. Аннотации для этого вполне подходят. |
||||||||||
|
|||||||||||
priam220 |
|
|||
![]() Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 291 Регистрация: 4.6.2010 Репутация: 7 Всего: 8 |
Java Рефлексия, - это возможность процедурного подхода в разработке на полностью объектном языке. Пришел к такому выводу. Я прав?
|
|||
|
||||
priam220 |
|
|||
![]() Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 291 Регистрация: 4.6.2010 Репутация: 7 Всего: 8 |
Skipy, спасибо тебе за такой развернутый ответ и за активность. Но все равно осталось много не понятного.
1. Хорошо понял только второй пример, с обработчиком ислкючений. Еще не совсем понял, зачем люди пишут instanceof в блоке catch(Throwable e){}, ведь в каждой книже по java написано, что исключения надо обрабатывать в поряке обратном наследования: т.е. catch(MyRuntimeException e){} catch(RuntimeException e){} Но в целом понятно. Наверное в верхнем уровне прилажения это действительно целесообразно, т.к. исключений может быть много. 2. Третий пример не понятен. <T> - эта шаблоны С++. Означает, что этот класс может обрабатывать переменный тип данных одной и той же логикой. В связи с чем мне не понятно, что означает new T(), и главное зачем нам нужен экземпляр параметризованного класса, параметр в который мы не передали. Это сообщение отредактировал(а) priam220 - 13.11.2010, 00:54 |
|||
|
||||
Skipy |
|
|||
![]() Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 487 Регистрация: 24.8.2006 Где: Москва, Россия Репутация: 6 Всего: 16 |
Это шаблоны в Java. Мы вообще-то говорим об этом языке. Судя по всему, Вам стоит для начала ознакомиться со всеми возможностями языка. По крайней мере с теми, которые существуют уже лет семь. Объяснять, зачем нужны такие конструкции, не вижу смысла - у Вас явный недостаток теории. P.S. Не совсем понимаю Ваши намерения. Вы хотите убедиться, что reflection - ненужный механизм? Или что? Я ЕЩЕ раз говорю - практически всё, что можно сделать через reflection, можно и без него. Но с ним - намного удобнее. Если не видите смысла, не используйте. Никто не заставляет. Когда реально понадобится - будете использовать. Это сообщение отредактировал(а) Skipy - 13.11.2010, 11:59 |
|||
|
||||
priam220 |
|
|||
![]() Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 291 Регистрация: 4.6.2010 Репутация: 7 Всего: 8 |
Звезды горят, значит это кому-нибудь нужно. Это понятно. Меня больше интересовал вопрос зачем оно кому-нибудь нужно. Но ситуация проясняется, спасибо. Недостаток конечно, но если бы его не было, никто ничего никогда не спрашивал бы. Вообще был бы благодарен, если бы объяснили последний пример с рефлексией, или ссылку почитать. Потому что не могу понять этот код:
MyClass <Integer> mc = new MyClass<Integer>(2); - понятно MyClass <String> mc = new MyClass<String>("2"); - понятно MyClass mc = new MyClass(Integer.class); - нет Это сообщение отредактировал(а) priam220 - 13.11.2010, 16:16 |
|||
|
||||
Skipy |
|
||||||||
![]() Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 487 Регистрация: 24.8.2006 Где: Москва, Россия Репутация: 6 Всего: 16 |
Я Вам по секрету скажу - компилятору тоже не до конца понятно. И потому он предупреждение на последнем варианте выдаст. Правильно - так:
Мы параметризуем класс типом Integer и класс этого же типа передаем в конструктор. Соответствие типов контролируется, вот это вызовет ошибку:
Нам нужен экземпляр Class<Integer>, чтобы создать экземпляр Intener внутри, через newInstance. Никак иначе мы это сделать не можем, в runtime нет сведений о типе T. Зато есть класс - Integer.class. А соответствие типов контролируется компилятором. |
||||||||
|
|||||||||
priam220 |
|
|||
![]() Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 291 Регистрация: 4.6.2010 Репутация: 7 Всего: 8 |
Теперь понял. Хороший пример. Но почему "никак иначе", а если так:
|
|||
|
||||
jk1 |
|
|||
![]() Эксперт ![]() ![]() ![]() Профиль Группа: Участник Сообщений: 1168 Регистрация: 17.10.2008 Где: Санкт-Петербург Репутация: 40 Всего: 75 |
Вы ветками if (obj instanceof Integer) будете перебирать все доступные типы из пространства имен? Если вы собираетесь параметризовать класс одним конкретным типом, то параметризация и не нужна - указывайте конкретный тип. Если предполагается 5-6 штук, то можно налепить 5-6 веток ветвления для разбора по типу, но это, как говорил Skipy, геморно и некрасиво. А вот если предполагается параметризация абсолютно любым классом, тут if'ов не напасешься. Это сообщение отредактировал(а) jk1 - 14.11.2010, 09:50 -------------------- Opinions are like assholes — everybody has one |
|||
|
||||
priam220 |
|
|||
![]() Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 291 Регистрация: 4.6.2010 Репутация: 7 Всего: 8 |
Речь шла о том, что "никак". И я думал, что не правильно понял пример.
Рефлексия влияет как то на скорость обработки кода? |
|||
|
||||
jk1 |
|
|||
![]() Эксперт ![]() ![]() ![]() Профиль Группа: Участник Сообщений: 1168 Регистрация: 17.10.2008 Где: Санкт-Петербург Репутация: 40 Всего: 75 |
Это и есть "никак". Или вы видите способ это сделать? -------------------- Opinions are like assholes — everybody has one |
|||
|
||||
priam220 |
|
|||
![]() Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 291 Регистрация: 4.6.2010 Репутация: 7 Всего: 8 |
Ну я не хотел бы вести полемику. Я думал, что речь идет о том, что это в принципе не возможно, а не не возмжно, потому что instanceof можно до утра писать. Это принципиальное различие, возможно, уже не играет роли, для тех, кто знает язык хорошо и имеет приличную практику, но для тех, кто его изучает, это различие важное...
Лучше ответьте, на следующие 2 вопроса: 1. что вы думаете о производительности кода с рефлексией. Есть ли какая то разница вообще. 2. Если говорить о практике, не представляю надобности типизированного Object'om класса. Т.е., конечно, Object'om можно типизировать класс, но обработка все равно ведь будет ограничена какими то типами (). Не предствляю себе класса, который обрабатывает "обсалютно любой" тип. Это что то должно быть сверх абстрактное? |
|||
|
||||
lazycat |
|
|||
Бывалый ![]() Профиль Группа: Участник Сообщений: 227 Регистрация: 15.7.2007 Репутация: 1 Всего: 1 |
||||
|
||||
Temdegon |
|
|||
![]() Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 429 Регистрация: 11.10.2008 Где: Minsk Репутация: 7 Всего: 9 |
Пример, на тему когда может быть нужно обработать "обсалютно любой" тип.
В библиотеке apache.commons.lang есть классы для реализации методов hashCode, equals и toString. Пример использования public String toString() { return ReflectionToStringBuilder.toString(this); } Одна строчка кода, вместо 10 (или 100, смотря сколько полей). Она одна для практически любого Entity и саппортить ее не нужно, даже если вы меняете поля класса. Аналогичные методы есть для hashCode и equals. Писать их вручную и постоянно подправлять мало кому нравится. Удобно? Мне кажется очень даже. |
|||
|
||||
Skipy |
|
||||||||
![]() Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 487 Регистрация: 24.8.2006 Где: Москва, Россия Репутация: 6 Всего: 16 |
Вы даже в теории не можете перечислить все классы. Просто потому, что я назову класс rerwerw.rtretret.weqwewq.rretre.ytrtyrete.reewrwe.MyClass - а Вы о таком при написании кода и понятия не имели. Кроме того, Ваш код предполагает создание экземпляра, который можно передать в конструктор. А мой код предназначен как раз для того, чтобы избавить вызывающий код от создания экземпляра. Почитайте про шаблон "Factory".
Всё далеко не так плохо. И уже давно. Мы используем reflection очень интенсивно, а проблем с производительностью у нас нет. И не только мы, кстати, Hibernate тоже так работает, например.
Это действительно невозможно в принципе. Просто по тому, что я могу написать параметризованный код - и отдать его в качестве библиотеки. А другой его возьмет - и параметризует СВОИМИ классами. О которых я ничего не знаю, да и знать не могу. А, следовательно, не смогу написать соответствующий instanceof. Кроме того, бесконечное количество instanceof Вы тоже не напишете - размер байткода метода, если мне не изменяет память, ограничен 64К. Это так, к слову.
А Object-ом, как правило, никто и не типизирует. А вот "любым объектом, наследующим Object" довольно часто. Очень в коллекциях полезно в определенных ситуациях. Это сообщение отредактировал(а) Skipy - 15.11.2010, 10:42 |
||||||||
|
|||||||||
priam220 |
|
|||
![]() Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 291 Регистрация: 4.6.2010 Репутация: 7 Всего: 8 |
Вот инфа по поводу производительнсоти. Кому лень смотреть основное:
метод действительно 64Kb максимум. Нашел баг на эту тему. Это сообщение отредактировал(а) priam220 - 15.11.2010, 16:27 |
|||
|
||||
priam220 |
|
||||||
![]() Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 291 Регистрация: 4.6.2010 Репутация: 7 Всего: 8 |
Но Factory будет, как полагаю, создаваться для классов из самой библиотеки, а так же их потомков. Следовательно, inctanceof можно сделать только для родительских классов из библиотеки, например (где A - библиотечный супер класс, а B - его потомок переопределенный пользователем):
А засетать пользовательские свойства, в таком случае, мы и с рефлексией не сможем. А если речь идет о том, что бы вернуть дефолтовый Instance, то в моем случае тоже проверок не надо (правда надо будет проверять в вызывающем методе, но мы то знаем какой тип передали), т.е. так работать будет тоже:
Если же мы захотим засетать объект в рефлексивной фабрике, то там тоже будет compile eror:
т.е. на момент создания не известно, что за объект сюда передасться и что за поля у него будут. Так же в моем случае, поскольку объект создается не в статическом методе библиотеки, а в вызываемом, то можно использовать только сетеры фабрики т.е. MyObject obj = new MyObject(); factory.setMyObjectDefault(obj); obj. getValue(); ведь объекты передаются по ссылке. И еще вот: MyFactory <A> mf = new MyFactory <A>(new B()); - можно. MyFactory2 <A> mf = new MyFactory2 <A> (B.class); - нет. Почему? нет ноты "му" ![]() |
||||||
|
|||||||
Skipy |
|
||||
![]() Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 487 Регистрация: 24.8.2006 Где: Москва, Россия Репутация: 6 Всего: 16 |
1. Ваши предположения Вам сослужат плохую службу. Когда не оправдаются. Я ПИСАЛ библиотеки, которые создавали классы, ничего не зная об их типах. Например, библиотеку по сериализации в XML. Очень душевно получилось на generic-ах. Сериализует-десериаллизует любые типы, создает классы по имени, и потом - экземпляры. С контролем типов, свойственным generic-ам. Код универсален. 2. Вы себе плохо представляете, что такое "фабрика". У Вас в нее передается уже созданный объект, а внутри ему устанавливается значение. Смысл фабрики - создавать объект внутри. Т.е. типа:
3. Даже если использовать такой вариант. У класса А - 843 наследника (число реальное). Напишите код через instanceof, который будет работать со всеми 843 классами. А я потом послушаю, что Вам скажет тот, кто будет его поддерживать. На этом предлагаю дискуссию закончить. До того момента, когда Вы получите опыт работы с Java хотя бы года три. Тогда у Вас станет меньше предположений и больше знаний о том, что, как и когда рельно делается. Очень надеюсь, что к этому моменту Вы перестанете считать написание даже 100 instanceof возможным. Это сообщение отредактировал(а) Skipy - 16.11.2010, 11:03 |
||||
|
|||||
priam220 |
|
|||
![]() Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 291 Регистрация: 4.6.2010 Репутация: 7 Всего: 8 |
Skipy, почитал вот тут. Понял, немного, о чем речь.
Полностью согласен. Но суть в том, что это замкнутый круг. Практики не будет, пока не поймешь, хотя бы в общем, что это. А не поймешь это, пока не будет практики. Поэтому, в любом случае, вначале надо разобраться просто с тем, хотябы как это работает и где. И Вы мне с этим помогли. За что БОЛЬШОЕ СПАСИБО. Мои прения прошу не воспринимать в серьез, это просто попытка разместить рефлексию в сознании там, где она должна быть. Еще раз спасибо. |
|||
|
||||
![]() ![]() ![]() |
Правила форума "Java" | |
|
Если Вам помогли, и атмосфера форума Вам понравилась, то заходите к нам чаще! С уважением, LSD, AntonSaburov, powerOn, tux, javastic. |
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей) | |
0 Пользователей: | |
« Предыдущая тема | Java: Общие вопросы | Следующая тема » |
|
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности Powered by Invision Power Board(R) 1.3 © 2003 IPS, Inc. |