Prefácio
Recentemente, durante o processo de aprendizado, descobri um problema. As classes abstratas não podem construir o objeto através de novos sem implementar todos os métodos abstratos, mas métodos abstratos podem ter seus próprios métodos de construção. Isso me confundiu. Como existe um método de construção e não pode ser criado através de novas, as classes abstratas podem ser instanciadas quando elas não se tornaram classes concretas?
Em Java, as classes abstratas não podem ser instantadas diretamente. No entanto, esse recurso das classes abstratas geralmente se torna um obstáculo problemático. Por exemplo, se eu quiser usar um proxy dinâmico para dar a uma classe abstrata a capacidade de executar métodos abstratos, haverá duas dificuldades: 1. O proxy dinâmico pode apenas criar um objeto proxy que implementa a interface, mas não um objeto que herda a classe abstrata. Para esta JVM padrão, existem algumas implementações, como o Javassist, que podem ser usadas para realizar isso usando ferramentas de bytecode (proxyfactory).
Se você deseja construir um objeto de classe abstrato no Android, você pode ter apenas new ClassName() {} ou herdado. No entanto, ambos os métodos não podem ser operados diretamente por seus objetos de classe, o que leva a alguns problemas que não podem atingir os recursos abstratos de que precisamos.
Aqui está uma descrição detalhada da cena mencionada no primeiro parágrafo:
Primeiro, existe um arquivo de interface definido da seguinte forma (amigos familiarizados com o Android podem ver que esta é uma interface de configuração da API fornecida para adaptar para gerar objetos proxy):
interface pública realapi {@get ("api1") observável <string> api1 (); @Get ("api2") observable <string> api2 (); @Get ("api3") observable <string> api3 (); //...OUS Métodos}Em seguida, escreva uma classe abstrata para implementar apenas um dos métodos da interface (usado para simular dados da interface):
@MockApipipublic Abstract Class Mockapi implementa realapi {observável <string> api3 () {return observable.just ("dados simulados"); }}Em seguida, precisamos ter uma ferramenta, como o MockManager, que combina nosso objeto realapi existente e a classe Mockapi para construir um objeto misto. Ao executar métodos já definidos em Mockapi, ele os executará diretamente. Quando Mockapi não definir o método, ele chama o método realapi. O método de chamada é aproximadamente:
Realapi api = mockmanager.build (realapi, makingapi.class);
Através do Javassist, é muito simples concluir a função acima. Crie um objeto proxyfactory, defina sua superclasse como MockAPI, filtre o método abstrato e defina o manipulador de métodos para chamar o objeto realapi com o mesmo nome e método do parâmetro. A implementação do código não será fornecida aqui.
Mas no Android, o método do Javassist será jogado
Causada por: java.lang.unsupportEdOperationException: não é possível carregar esse tipo de arquivo de classe em java.lang.classloader.defineclass (classe de classe.java:520) em java.lang.reflect.method.invoke (método nativo) javassist.util.proxy.factoryhelper.toclass2 (factoryhelper.java:182)
Exceções semelhantes. O motivo é provavelmente que a implementação e os padrões das máquinas virtuais no Android são um pouco diferentes, então aqui transformamos a direção para outra direção do processador de anotação de geração dinâmica de código.
Se você usar o processador de anotação para implementá -lo, a ideia é muito mais simples, mas o processo ainda é um pouco tortuoso:
Primeiro defina uma anotação para marcar a classe abstrata que precisa ser construída
@Target (elementType.type)@documentado@retention (retentionpolicy.source) public @interface Mockapi {} O processador obtém o objeto elemento da classe com base na anotação, que é um objeto semelhante a uma classe. Como a classe ainda não existe no estágio de pré -compilação, é impossível obter o objeto de classe exigido pelo tempo de execução usando Class.forName . No entanto, o elemento fornece métodos semelhantes aos relacionados à reflexão de classe e também existem diferenças como TypeElement e ExecutableElement. Quais são os métodos abstratos da classe abstrata anotada usando o objeto elemento para analisar a classe abstrata anotada, gerar uma classe de implementação (não abstrato) que herda a classe e implemente todos os métodos abstratos da classe. Como esses métodos abstratos não serão realmente usados, eles só precisam ser capazes de compilar e passar. A maneira como escolhi é que cada corpo de método lança uma exceção, provocando que o método é um método abstrato e não pode ser chamado diretamente. O método de geração de código pode usar algumas ferramentas para simplificar o trabalho, como o Autoprocessor e o Javapoet, que implementa especificamente o código do projeto no final do texto de referência. O código gerado é aproximadamente assim:
// O nome da classe gerado é nomeado com o sufixo do nome da classe original + "$ implicista" para evitar conflitos com outros nomes de classe. Essa restrição também é usada para refletir a classe Public Final Class Mockapi $ implic estende Mockapi {@Override public observable <string> API1 () {THROW NOVA ILGLELGALSTATEEXCECTION ("API1 () é um método abstrato!"); } @Override public observable <string> api2 () {tiro new ilegalStateException ("API2 () é um método abstrato!"); }}Reflita a classe de implementação com base no nome da classe da classe abstrata e, em seguida, construa um objeto de implementação com base na reflexão chamando seu método construtor.
// Obtenha o objeto que gera o código de construção estática privada <t> t getImplObject (classe <T> cls) {try {return (t) class.ForName (cls.getName () + "$ implic"). NewInstance (); } catch (Exceção e) {return null; }}Construa um proxy dinâmico, transmita -o para o objeto real do RealApi e o objeto de implementação da classe abstrata construída na etapa anterior e determine qual objeto está proxyndo seu comportamento de método com base na definição na classe abstrata: se houver uma definição na classe abstrata, ou seja, o método não é um método abstrato, o objeto de implementação da classe abstrata será executado; Caso contrário, ele será executado pelo objeto real da interface.
public static <origem, mock estende origem> origem compilação (origem final de origem, classe final <mock>class) {// Se a classe simulada estiver marcada como fechada, ele retornará diretamente o objeto de interface real se (! isenable (mockclass)) {return orige; } Final MockObject = getImplObject (MockClass); Classe <?> Originclass = Origin.getClass (). GetInterfaces () [0]; return (origem) proxy.NewProxyInstance (origin -class}, newspocationHandler () {@Override Public Object Invoke (objeto o, método, Método, Objeto [] Objetos) lança a classe {// zombar o mesmo nome do mesmo nome; O MethodClass (MethodCerete, o que é um dos melhores e os que estão sendo feitos pelo menos termos de um que você. MockMethod.inVoke (MockObject, Objetos);Depois de concluir o trabalho acima, você pode usar o método de construção para construir um objeto proxy que misture interfaces reais e métodos de classe abstrata, conforme mencionado no início. Embora a classe de chamada seja essencialmente codificada, ela é gerada automaticamente pelo processador de anotação sem manutenção manual. Em termos de uso, é basicamente o mesmo que o uso da implementação do Javassist.
Usei o método ao qual pertenço neste artigo para implementar uma ferramenta que simula solicitações de retrofit (existe um link no final do artigo), mas, em essência, ele pode ser usado para implementar muitas necessidades que exigem a construção de classes abstratas e mais cenários de uso ainda precisam ser explorados.
A implementação do código-fonte mencionada no artigo pode ser encontrada no projeto ROTROFIT-MOCK-RESULT ou do download local;
Resumir
O acima é o conteúdo inteiro deste artigo. Espero que o conteúdo deste artigo tenha certo valor de referência para o estudo ou trabalho de todos. Se você tiver alguma dúvida, pode deixar uma mensagem para se comunicar. Obrigado pelo seu apoio ao wulin.com.