Я переписываю фреймворк, изначально созданный на C#, на Java, и это меня озадачило. Это метод, использующий отражение для возврата любого свойства в классе, который реализует определенный интерфейс с помощью LINQ:
public List<TInterface> GetElementsOfType<TInterface>()
{
return GetType().GetProperties()
.Where(x => typeof(TInterface).IsAssignableFrom(x.PropertyType))
.Select(x => x.GetValue(this, null)).OfType<TInterface>()
.ToList();
}
Я пытаюсь воссоздать на Java, и пока это есть. Не слишком уверен, правда ли это ?:
public <T> List<?> GetElementsOfType(Class<T> klazz) {
Class<?> props = this.getClass();
List<T> elementsOfType = new ArrayList<>();
try {
Field fieldlist[] = props.getDeclaredFields();
for (Field aFieldlist : fieldlist) {
if (aFieldlist.getType().isAssignableFrom(klazz)){
elementsOfType.add((T)aFieldlist);
}
}
} catch (Exception e) {
return null;
}
return elementsOfType;
}
Обновление: спасибо всем за вашу помощь. Кажется, это работает для меня, хотя непроверенное приведение вызывает предупреждение, которое мне пришлось подавить:
@SuppressWarnings("unchecked")
public <T> List<T> GetElementsOfType(Class<T> klazz) {
Class<?> props = this.getClass();
List<T> elementsOfType = new ArrayList<>();
try {
Field fieldlist[] = props.getDeclaredFields();
for (Field aFieldlist : fieldlist) {
if (klazz.isAssignableFrom(aFieldlist.getType())){
elementsOfType.add((T) aFieldlist.get(this));
}
}
} catch (Exception e) {
return elementsOfType;
}
return elementsOfType;
}
}
Да, использую Java 8, в потоки не смотрел
Вы хотите, чтобы аргументы для isAssignableFrom были в том же порядке, что и в C#




В Java свойство - это не поле. Свойство определяется как общедоступный нестатический метод чтения и, если это свойство не предназначено только для чтения, как общедоступный нестатический метод записи. Экземпляр класса с одним или несколькими такими свойствами называется Java-компонентом.
Вы можете проверить свойства с помощью пакета java.beans, начиная с Интроспектор:
try {
BeanInfo beanInfo = Introspector.getBeanInfo(props, Object.class);
for (PropertyDescriptor prop : beanInfo.getPropertyDescriptors()) {
if (klazz.isAssignableFrom(prop.getPropertyType())) {
elementsOfType.add(klazz.cast(prop.getReadMethod().invoke(this)));
}
}
} catch (IntrospectionException | ReflectiveOperationException e) {
throw new RuntimeException(e);
}
Поскольку Java использует проверенные исключения, в этом случае вы не сможете легко использовать Streams для написания LINQ-подобного кода. Можно, но громоздко. И не стоит заморачиваться, учитывая, что приведенный выше код довольно лаконичен.
(Причина использования Object.class в Introspector.getBeanInfo(klazz, Object.class) заключается в том, что нам не нужны свойства объекта, а именно свойство class объекта только для чтения, определенное в Object.getClass ().)
К сожалению, это просто каждый раз вызывает IntrospectionException. Любые идеи? Я называю это так: List <Editable> editableElements = bingHomePage.GetElementsOfType (Editable.class);
В чем заключается сообщение об исключении IntrospectionException? Содержит ли его трассировка стека какие-либо разделы «Причина»?
Думаю, это может быть связано с этим stackoverflow.com/questions/4438815/…
Эта ошибка, по-видимому, связана с наличием методов get и set в разных классах иерархии наследования. Это верно для вашего класса реквизита? В противном случае более вероятно, что исключение на самом деле сообщает вам, в чем проблема.
Спасибо, да, у меня возникают проблемы с чтением банкомата трассировки стека (с использованием кода VS и похоже, что там есть какая-то проблема), но это звучит примерно правильно. Хорошие новости. Теперь он работает, используя мой исходный код (см. Обновление), но я обязательно попытаюсь его реорганизовать, чтобы ваш подход заработал.
если вы используете java 8, вы можете посмотреть потоки java 8, он может в значительной степени делать то же самое, что и версия C# выше