Казалось бы ответ очевиден:
(new Reflections("package")).getSubTypesOf(SuperClass.class)
Однако эта конструкция находит не всех наследников, в случае, если иерархия разнесена на несколько пакетов.
Есть следующие классы:
package1.ParentClass extemds SuperClass
package2.ChildClass extends ParentClass
Пакеты package1
и package2
не вложенные.
Конструкция
(new Reflections("package1")).getSubTypesOf(SuperClass.class)
Ожидаемо вернёт package1.ParentClass
А вот конструкция
(new Reflections("package2")).getSubTypesOf(SuperClass.class)
Наш package2.ChildClass
не вернёт, хотя это очевидный наследник SuperClass
.
Я понимаю. что могу в ручную пробежаться по всем классам пакета и собрать нужные. Но неужели нет стандартного способа?
И ещё, объясните, почему по умолчанию ChildClass
не находится? Для меня это было очень неожиданное поведение от org.reflections.Reflections
.
UPD:
Изучил исходники ядра org.reflections, всё стало на свои места.
Если кратко, java именно так и реализует Reflections.
У каждого класса в рефлексии есть только ссылка на родителя. Поэтому поиск подклассов в любом случае перебор.
Почему в этом переборе нет супер классов из иных пакетов — вопрос отдельный. Так реализовано.
Для каждой конкретной задачи нужно использовать оптимальное решение. Но хотелось бы услышать о уже существующих решениях, которые позволяют найти всех потомков, кроме java org.reflections.
UPD: Ещё один интересный и нетрудоёмкий способ.
Reflections reflections = new Reflections("package1", new SubTypesScanner())
Set<Class<?>> subTypes = new HashSet<>();
for (String className : reflections.getStore().get(SubTypesScanner.class.getSimpleName()).values()) {
try {
Class subType = Class.forName(className);
if (SuperClass.class.isAssignableFrom(subType)) {
subTypes.add(subType);
}
} catch (ClassNotFoundException e) {
throw new RuntimeException("Этого не может быть:)", e);
}
}
return subTypes;
Данное решение перебирает все классы пакета (кроме наследников object)
reflections.getStore().get(SubTypesScanner.class.getSimpleName()).values()
и проверяет на то, что они являются наследником или реализуют SuperClass
SuperClass.class.isAssignableFrom(subType)
По производительности, по крайней мере, лучше, чем поиск по всем пакетам и последующая фильтрация
Казалось бы ответ очевиден:
(new Reflections(«package»)).getSubTypesOf(SuperClass.class)
Однако эта конструкция находит не всех наследников, в случае, если иерархия разнесена на несколько пакетов.
Есть следующие классы:
package1.ParentClass extemds SuperClass
package2.ChildClass extends ParentClass
Пакеты package1 и package2 не вложенные.
Конструкция
(new Reflections(«package1»)).getSubTypesOf(SuperClass.class)
Ожидаемо вернёт package1.ParentClass
А вот конструкция
(new Reflections(«package2»)).getSubTypesOf(SuperClass.class)
Наш package2.ChildClass не вернёт, хотя это очевидный наследник SuperClass
Я понимаю. что могу в ручную пробежаться по всем классам пакета и собрать нужные. Но неужели нет стандартного способа?
И ещё, объясните, почему по умолчанию ChildClass не находится? Для меня это было очень неожиданное поведение от org.reflections.Reflections
UPD:
Изучил исходники ядра org.reflections, всё стало на свои места.
Если кратко, java именно так и реализует Reflections.
У каждого класса в рефлексии есть только ссылка на родителя. Поэтому поиск подклассов в любом случае перебор.
Почему в этом переборе нет супер классов из иных пакетов — вопрос отдельный. Так реализовано.
Для каждой конкретной задачи нужно использовать оптимальное решение. Но хотелось бы услышать о уже существующих решениях, которые позволяют найти всех потомков, кроме java org.reflections.
UPD: Ещё один интересный и нетрудоёмкий способ.
Reflections reflections = new Reflections(«package1», new SubTypesScanner())
Set> subTypes = new HashSet<>();
for (String className : reflections.getStore().get(SubTypesScanner.class.getSimpleName()).values()) {
try {
Class subType = Class.forName(className);
if (SuperClass.class.isAssignableFrom(subType)) {
subTypes.add(subType);
}
} catch (ClassNotFoundException e) {
throw new RuntimeException(«Этого не может быть:)», e);
}
}
return subTypes;
Данное решение перебирает все классы пакета (кроме наследников object)
reflections.getStore().get(SubTypesScanner.class.getSimpleName()).values()
и проверяет на то, что они являются наследником или реализуют SuperClass
SuperClass.class.isAssignableFrom(subType)
По производительности, по крайней мере, лучше, чем поиск по всем пакетам и последующая фильтрация
Ответ
И ещё, объясните, почему по умолчанию ChildClass не находится?
Причина в том, что класс ChildClass является не прямым наследником SuperClass, а через класс ParentClass.
Reflections не уходит рекурсивно на проверку «родителей-родителей» и так далее, поэтому для обнаружения факта наследования через «промежуточные» классы необходимо загрузить пакеты со всеми «промежуточными» классами. В данном случае для того чтобы определить факт наследования ChildClass от SuperClass необходимо так же загрузить ParentClass. Лишние классы из полученного множества(Set) можно отфильтровать по имени пакета.
(new Reflections(«package1″,»package2»))
.getSubTypesOf(SuperClass.class)
.stream()
.filter(c->c.getPackage().getName().equals(«package2»)).collect(Collectors.toSet());
1) Если неизвестен пакет «package1» то можно загрузить реализации из всех пакетов и потом отфильтровать по нужному пакету «package2»:
Set
> s = new Reflections(
ClasspathHelper.forClass(SuperClass.class))
.getSubTypesOf(SuperClass.class)
.stream()
.filter(c->c.getPackage().getName().equals(«package2»))
.collect(Collectors.toSet());
или
Set> s = new Reflections(
new ConfigurationBuilder()
.setUrls(ClasspathHelper.forClass(SuperClass.class))
.filterInputsBy(new FilterBuilder().excludePackage(«package2»)))
.getSubTypesOf(SuperClass.class);
2) В качестве более производительной альтернативы можно воспользоваться стандартными средствами “java core” и получить все файлы-классы пакета и их уже рекурсивно проверить на наличие искомого наследника.
public static Set> loadClasses(String packageName)
throws ClassNotFoundException {
Set> classes = new HashSet<>();
URL resource = Thread.currentThread()
.getContextClassLoader()
.getResource(packageName.replace(‘.’, ‘/’));
File directory
= new File(resource.getFile());
if (!directory.exists()) {
return classes;
}
File[] files = directory.listFiles();
if (files == null || files.length == 0) {
return classes;
}
for (File file : files) {
//в другие пакеты уходить ненужно
if (file.isFile() && file.getName().endsWith(«.class»)) {
classes.add(Class
.forName(String.format(«%s.%s»,
packageName,
file.getName().substring(0, file.getName().indexOf(«.»)))));
}
}
return classes;
}
public static boolean checkAllParents(Class
type, Class hasParentType) {
Class parent = type.getSuperclass();
if (parent == Object.class) {
return false;
}
if (parent.getClass() == hasParentType.getClass()) {
return true;
}
return checkAllParents(parent, hasParentType);
}
Set
> s = loadClasses(«package2»).stream()
.filter(i->checkAllParents(i, SuperClass.class))
.collect(Collectors.toSet());
Asked
11 years, 1 month ago
Viewed
16k times
I would use http://code.google.com/p/reflections/
Using Reflections you can query your metadata such as:
- get all subtypes of some type
- get all types/methods/fields annotated with some annotation, w/o annotation parameters matching
- get all resources matching matching a regular expression
This can be used in an indexed or cached mode. As @Jagger suggests, a brute force search of every class is relatively slow. You can also limit the search by package e.g. com.mycom.*
answered Apr 23, 2012 at 8:05
Peter LawreyPeter Lawrey
524k77 gold badges749 silver badges1128 bronze badges
3
0 / 0 / 0 Регистрация: 12.04.2011 Сообщений: 5 |
|
1 |
|
работа с классами — получение наследников12.04.2011, 17:40. Показов 2013. Ответов 3
имеем набор скомпилированных Java классов. Эти классы представляют собой иерархию. Все классы находятся в одном java package. Необходимо динамически загружать и анализировать иерархию классов. При указании имени класса необходимо получить имена всех классов данного пакета, которые являются наследниками заданного класса/интерфейса. Предложите идеи… заранее благодрарен
0 |
unknown |
|
12.04.2011, 17:44 |
2 |
механизм RTTI |
0 / 0 / 0 Регистрация: 12.04.2011 Сообщений: 5 |
|
12.04.2011, 17:52 [ТС] |
3 |
а возможно поподробнее, я новичок в работе с Java :-<
0 |
unknown |
|
12.04.2011, 18:50 |
4 |
http://dmitry.ints.net/library/prog/link/Java/Java/Chapter12.html можно прослеживать иерархию от текущего класса к его предкам, но не наоборот. для этого нужно организовать через ссылки на |
IT_Exp Эксперт 87844 / 49110 / 22898 Регистрация: 17.06.2006 Сообщений: 92,604 |
12.04.2011, 18:50 |
Помогаю со студенческими работами здесь Работа с классами
Работа с классами Работа с классами Определите значение переменных а, х, с после выполнения следующих команд: Искать еще темы с ответами Или воспользуйтесь поиском по форуму: 4 |
Если у меня есть какой-то абстрактный (или нет, не важно) класс — могу ли я найти все классы, которые наследуются от этого класса?
2 ответа
Лучший ответ
Как указал в комментарии, это называется иерархией типов. Чтобы найти это в IntelliJ, либо используйте ярлык ^ + H , либо перейдите в раздел «Навигация и тип иерархии».
2
Community
23 Май 2017 в 12:12
Это может зависеть от привязки вашего ключа, но из того, что я помню по умолчанию в Idea, это ctrl + H (или эквивалент ctrl на вашей платформе).
Если это не так, то вам следует знать ярлык : ctrl + shift + A , который позволяет вам найти действия (и перечисляет их с привязкой клавиш) на основе случайного запроса!
1
Mateusz Dymczyk
4 Фев 2015 в 01:28