Como alguém tenta encontrar todas as subclasses de uma determinada classe (ou todos os implementadores de uma determinada interface) em Java? A partir de agora, tenho um método para fazer isso, mas acho bastante ineficiente (para dizer o mínimo). O método é:
- Obtenha uma lista de todos os nomes de classe que existem no caminho da classe
- Carregue cada classe e teste para ver se é uma subclasse ou implementador da classe ou interface desejada
No Eclipse, há um recurso interessante chamado Hierarquia de Tipos que consegue mostrar isso com bastante eficiência. Como se faz e faz de forma programática?
Respostas:
Não há outra maneira de fazer isso além do que você descreveu. Pense nisso - como alguém pode saber quais classes estendem o ClassX sem verificar cada classe no caminho de classe?
O Eclipse pode apenas falar sobre as super e subclasses no que parece ser uma quantidade "eficiente" de tempo, porque ele já possui todos os dados de tipo carregados no ponto em que você pressiona o botão "Exibir na Hierarquia de Tipos" (uma vez que é constantemente compilando suas aulas, sabe tudo sobre o caminho de classe, etc).
fonte
reflections.getSubTypesOf(aClazz))
linkA varredura de classes não é fácil com Java puro.
A estrutura spring oferece uma classe chamada ClassPathScanningCandidateComponentProvider que pode fazer o que você precisa. O exemplo a seguir encontraria todas as subclasses de MyClass no pacote org.example.package
Esse método tem o benefício adicional de usar um analisador de bytecode para encontrar os candidatos, o que significa que ele não carregará todas as classes que ele varre.
fonte
Isso não é possível usando apenas a API Java Reflections integrada.
Existe um projeto que faz a digitalização e indexação necessárias do seu caminho de classe para que você possa acessar essas informações ...
Reflexões
(aviso de isenção de responsabilidade: eu não o usei, mas a descrição do projeto parece ser adequada às suas necessidades.)
fonte
Não esqueça que o Javadoc gerado para uma classe incluirá uma lista de subclasses conhecidas (e para interfaces, classes de implementação conhecidas).
fonte
Tente ClassGraph . (Isenção de responsabilidade, eu sou o autor). O ClassGraph suporta a varredura de subclasses de uma determinada classe, em tempo de execução ou em tempo de construção, mas também muito mais. O ClassGraph pode criar uma representação abstrata de todo o gráfico de classes (todas as classes, anotações, métodos, parâmetros de métodos e campos) na memória, para todas as classes no caminho de classe ou para classes em pacotes na lista de permissões, e você pode consultar esse gráfico de classe você quer. O ClassGraph suporta mais mecanismos de especificação de caminho de classe e carregadores de classes do que qualquer outro scanner, e também funciona perfeitamente com o novo sistema de módulo JPMS, portanto, se você basear seu código no ClassGraph, seu código será portátil no máximo. Veja a API aqui.
fonte
Eu fiz isso há vários anos. A maneira mais confiável de fazer isso (por exemplo, com APIs Java oficiais e sem dependências externas) é escrever um doclet personalizado para produzir uma lista que possa ser lida em tempo de execução.
Você pode executá-lo na linha de comando da seguinte maneira:
ou execute-o a partir desta formiga:
Aqui está o código básico:
Para simplificar, removi a análise de argumentos da linha de comando e estou escrevendo no System.out em vez de em um arquivo.
fonte
Sei que estou alguns anos atrasado para esta festa, mas me deparei com essa pergunta tentando resolver o mesmo problema. Você pode usar a pesquisa interna do Eclipse de forma programática, se estiver escrevendo um Plug-in do Eclipse (e, assim, tirar proveito do cache, etc), para encontrar classes que implementam uma interface. Aqui está o meu primeiro corte (muito difícil):
O primeiro problema que vejo até agora é que estou capturando apenas classes que implementam diretamente a interface, não todas as subclasses - mas uma pequena recursão nunca prejudica ninguém.
fonte
Tendo em mente as limitações mencionadas nas outras respostas, você também pode usar o openpojo's
PojoClassFactory
( disponível no Maven ) da seguinte maneira:Onde
packageRoot
está a String raiz dos pacotes que você deseja pesquisar (por exemplo,"com.mycompany"
ou mesmo apenas"com"
), eSuperclass
é o seu supertipo (isso também funciona nas interfaces).fonte
Acabei de escrever uma demo simples para usar as
org.reflections.Reflections
subclasses de get da classe abstract:https://github.com/xmeng1/ReflectionsDemo
fonte
Dependendo de seus requisitos específicos, em alguns casos, o mecanismo do carregador de serviço do Java pode alcançar o que você procura.
Em resumo, ele permite que os desenvolvedores declarem explicitamente que uma classe subclasse alguma outra classe (ou implementa alguma interface) listando-a em um arquivo no
META-INF/services
diretório do arquivo JAR / WAR . Em seguida, ele pode ser descoberto usando ajava.util.ServiceLoader
classe que, quando recebe umClass
objeto, gera instâncias de todas as subclasses declaradas dessa classe (ou, se issoClass
representa uma interface, todas as classes que implementam essa interface).A principal vantagem dessa abordagem é que não há necessidade de varrer manualmente todo o caminho de classe em busca de subclasses - toda a lógica de descoberta está contida na
ServiceLoader
classe e apenas carrega as classes explicitamente declaradas noMETA-INF/services
diretório (nem todas as classes no caminho de classe) .Existem, no entanto, algumas desvantagens:
META-INF/services
diretório Esse é um ônus adicional para o desenvolvedor e pode estar sujeito a erros.ServiceLoader.iterator()
gera instâncias de subclasse, não seusClass
objetos. Isso causa dois problemas:Aparentemente, o Java 9 abordará algumas dessas deficiências (em particular, as relacionadas à instanciação de subclasses).
Um exemplo
Suponha que você esteja interessado em encontrar classes que implementam uma interface
com.example.Example
:A classe
com.example.ExampleImpl
implementa essa interface:Você declararia que a classe
ExampleImpl
é uma implementaçãoExample
criando um arquivo queMETA-INF/services/com.example.Example
contém o textocom.example.ExampleImpl
.Em seguida, você pode obter uma instância de cada implementação de
Example
(incluindo uma instância deExampleImpl
) da seguinte maneira:fonte
Deve-se notar também que, é claro, isso encontrará apenas todas as subclasses existentes no seu caminho de classe atual. Presumivelmente, isso é bom para o que você está vendo no momento, e é provável que você considere isso, mas se em algum momento você tiver liberado uma não-
final
classe para a natureza (para níveis variados de "natureza"), é inteiramente possível que alguém escreveu sua própria subclasse que você não conhecerá.Portanto, se você estava querendo ver todas as subclasses porque deseja fazer uma alteração e vai ver como isso afeta o comportamento das subclasses - lembre-se das subclasses que não pode ver. Idealmente, todos os seus métodos não privados e a própria classe devem estar bem documentados; faça alterações de acordo com esta documentação sem alterar a semântica dos métodos / campos não privados e suas alterações deverão ser compatíveis com versões anteriores, para qualquer subclasse que siga pelo menos a sua definição de superclasse.
fonte
O motivo pelo qual você vê uma diferença entre sua implementação e o Eclipse é porque você varre cada vez, enquanto o Eclipse (e outras ferramentas) varre apenas uma vez (durante o carregamento do projeto na maioria das vezes) e cria um índice. Na próxima vez que você solicitar os dados, eles não serão verificados novamente, mas observe o índice.
fonte
Estou usando uma biblioteca de reflexão, que verifica seu caminho de classe em todas as subclasses: https://github.com/ronmamo/reflections
É assim que isso seria feito:
fonte
Adicione-os a um mapa estático dentro (this.getClass (). GetName ()) do construtor de classes pai (ou crie um padrão), mas isso será atualizado em tempo de execução. Se a inicialização lenta for uma opção, você pode tentar esta abordagem.
fonte
Você pode usar a biblioteca org.reflections e, em seguida, criar um objeto da classe Reflections. Usando este objeto, você pode obter uma lista de todas as subclasses de determinada classe. https://www.javadoc.io/doc/org.reflections/reflections/0.9.10/org/reflections/Reflections.html
fonte
Eu precisava fazer isso como um caso de teste, para ver se novas classes foram adicionadas ao código. Foi o que eu fiz
fonte