Este artigo tem como objetivo dar uma introdução abrangente ao mecanismo de reflexão Java. Espero que, durante este artigo, você tenha um entendimento abrangente do conteúdo relevante da reflexão Java.
Antes de ler este artigo, você pode se referir a " Recuperando os genéricos do Java " .
Prefácio
O mecanismo de reflexão Java é uma função muito poderosa. As reflexões podem ser vistas em muitos projetos em larga escala, como Spring e Mybatis. Através do mecanismo de reflexão, podemos obter informações do tipo de objeto durante a operação. Usando esse recurso, podemos implementar padrões de design, como modo de fábrica e modo proxy, e também podemos resolver problemas de angustiação, como o apagamento genérico de Java. Neste artigo, aplicaremos o mecanismo de reflexão Java da perspectiva das aplicações práticas.
Base de reflexão
PS: Este artigo exige que os leitores tenham um certo grau de entendimento da API do mecanismo de reflexão. Se você não foi exposto a ele antes, é recomendável olhar primeiro para o início rápido do documento oficial.
Antes de aplicar o mecanismo de reflexão, vamos primeiro ver como obter a Class de reflexão correspondente a um objeto. Em Java, temos três maneiras de obter a classe de reflexão de um objeto.
Pelo método getClass
Em Java, cada Object possui um método getClass . Através do método getClass, podemos obter a classe de reflexão correspondente deste objeto:
String s = "ziwenxie"; classe <?> C = s.getclass ();
Também podemos chamar o método estático forName Class :
Classe <?> C = classe.ForName ("java.lang.string"); Ou podemos usar .class diretamente:
Classe <?> C = string.class;
No início do artigo, mencionamos que um dos principais benefícios da reflexão é que ele nos permite obter informações do tipo de objeto durante a operação. Vamos dar uma olhada em detalhes com um exemplo.
Primeiro, criamos uma nova interface A sob typeinfo.interfacea :
pacote typeInfo.interfacea; interface pública a {void f (); } Em seguida, criamos uma nova interface C no pacote typeinfo.packageaccess . A interface C herda da interface A e também criamos vários outros métodos para teste. Observe que as permissões dos seguintes métodos são diferentes.
pacote typeInfo.packageAccess; importar tipoInfo.interfacea.a; classe C implementa um {public void f () {System.out.println ("public cf ()"); } public void g () {System.out.println ("public CG ()"); } void protegido V () {System.out.println ("CV () protegido"); } void u () {System.out.println ("pacote cu ()"); } private void w () {System.out.println ("private cw ()"); }} classe pública hiddenc {public static a makea () {return c (); }} No método callHiddenMethod() , usamos várias novas APIs, onde getDeclaredMethod() é usado para obter um método que a classe de classe se refere ao objeto de acordo com o nome do método e, em seguida, podemos acionar os métodos relacionados do objeto chamando invoke() :
pacote typeInfo; importação typeInfo.interfacea.a; importar tipoInfo.packageAccess.hiddenc; importar java.lang.reflect.method; classe pública hiddenimplementation {public static void main (string [] args) lança a exceção {a a = hiddenc.makea (); af (); System.out.println (a.getclass (). GetName ()); // opa! A reflexão ainda nos permite ligar para g (): calhdendmethod (a, "g"); // e até métodos que são menos acessíveis! callhiddenmethod (a, "u"); calhiddenmethod (a, "v"); callhiddenmethod (a, "w"); } void estático calhdendmethod (objeto a, string métodname) lança a exceção {método g = a.getclass (). getDecLaredMethod (MethodName); g.setAccessible (verdadeiro); g.invoke (a); }} A partir dos resultados da saída, podemos ver que, se é public , default , protect ou pricate , podemos chamá -lo livremente através da classe de reflexão. Obviamente, somos apenas para mostrar o poderoso poder da reflexão, e essa técnica não é recomendada no desenvolvimento real.
public cf () typeInfo.packageAccess.cpublic cg () pacote cu () protegido cv () private cw () private cw ()
Temos o seguinte cenário de negócios. Temos uma List<Class<? extends Pet>> . Precisamos contar quantos Pet específicos existem nesta aula de coleção. Devido ao apagamento genérico de Java, definitivamente não é possível prestar atenção à prática semelhante à List<? extends Pet> , porque depois que o compilador faz uma verificação de tipo estático, a JVM tratará todos os objetos da coleção como Pet durante a corrida, mas não saberá se Pet representa Cat ou Dog ; portanto, o tipo de informação do objeto é realmente perdido durante a corrida. PS: Sobre o apagamento genérico: tenho uma explicação detalhada no artigo anterior. Amigos interessados podem dar uma olhada.
Para implementar nosso exemplo acima, primeiro definimos várias classes:
public class Pet estende individual {public pet (nome da string) {super (nome); } public pet () {super (); }} classe pública Cat estende PET {public Cat (Nome da String) {super (nome); } public Cat () {super (); }} classe pública Dog estende PET {public Dog (Nome da String) {super (nome); }} classe pública Egyptianmau estende o gato {public Egyptianmau (nome da string) {super (nome); } public EgyptianMau () {super (); }} classe pública Mutt estende o cachorro {public mutt (nome da string) {super (nome); } public mutt () {super (); }} Pet acima herda do Individual . A implementação da classe Individual é um pouco mais complicada. Implementamos Comparable e redefinimos as regras de comparação de classe. Se não entendemos muito bem, isso não importa. Nós o abstraímos, por isso não importa se não entendemos o princípio da implementação.
Public class implementações individuais comparáveis <fivilmente> {counter privado estático long = 0; Private Final Long Id = contador ++; nome de string privado; // O nome é público opcional individual (nome da string) {this.name = name; } public individual () {} public string tostring () {return getClass (). getSImpleName () + (nome == null? "": "" + nome); } public long id () {return id; } public boolean é igual (objeto o) {return o instância de individual && id == ((individual) o) .id; } public int hashCode () {int resultado = 17; if (nome! = null) {resultado = 37 * resultado + name.hashcode (); } resultado = 37 * resultado + (int) id; resultado de retorno; } public int compareto (Individual arg) {// compare pela classe Nome primeiro: string primeiro = getClass (). getSImplename (); String argfirst = arg.getclass (). GetSImpleName (); int primeiroCompare = primeiro.compareto (argfirst); if (FirstCompare! = 0) {return FirstCompare; } if (name! = null && arg.name! = null) {int secundarycompare = name.compareto (arg.name); if (SECENDCOMPARE! = 0) {return secundáriocompare; }} return (arg.id <id? -1: (arg.id == id? 0: 1)); }} Abaixo está uma classe abstrata PetCreator . No futuro, podemos obter diretamente a coleta de classes Pet relacionadas chamando arrayList() . Aqui usamos o método newInstance() que não mencionamos acima. Ele retornará uma instância da classe a que a classe realmente se refere. O que isto significa? Por exemplo, declarar new Dog().getClass().newInstance() e Direct new Dog() são equivalentes.
classe public abstrata Petcreator {private Rand Rand = novo aleatório (47); // A lista dos diferentes gettypes do PET para criar: Lista de Resumo Public <classe <? estende PET >> getTypes (); public Pet Randompet () {// Crie um Pet Random Int N = Rand.NextInt (getTypes (). size ()); tente {return getTypes (). get (n) .NewInstance (); } Catch (InstantionActionException e) {Lança a nova RunTimeException (e); } catch (ilegalAccessException e) {lança a nova RunTimeException (e); }} public pet [] createArray (int size) {pet [] resultado = novo PET [size]; for (int i = 0; i <tamanho; i ++) {resultado [i] = Randompet (); } resultado de retorno; } public ArrayList <pet> ArrayList (int size) {ArrayList <Tet> resultado = new ArrayList <Pet> (); Coleções.addall (resultado, createArray (tamanho)); resultado de retorno; }} Em seguida, vamos implementar a classe abstrata acima e explicar o código a seguir. No código a seguir, declaramos duas classes de coleta, allTypes e types , entre os quais allTypes contém todas as classes declaradas acima, mas nossos tipos específicos são na verdade apenas dois tipos, ou seja, Mutt e EgypianMau , então o animal de estimação que realmente precisamos obter new são apenas os tipos contidos nos types . No futuro, podemos obter os tipos contidos nos types chamando getTypes() .
classe pública literalpetcreator estende PetCreator {@suppresswarnings ("desmarcado") Lista final estática pública <classe <? estende PET >> allTypes = Coleções.unmodifiablelist (Arrays.asList (Pet.class, Dog.class, Cat.class, Mutt.class, Egyptianmau.class)); Lista final estática privada <classe <? estende PET >> TIPOS = ALLTYPES.SUBLIST (allTypes.indexof (mutt.class), allTypes.size ()); Lista pública <classe <? estende PET >> getTypes () {retorna tipos; }} A lógica geral foi concluída e, finalmente, implementamos TypeCounter usada para contar o número de classes Pet relevantes no conjunto. Explique isAssignalbeFrom() , que pode determinar que uma classe de reflexão é uma subclasse ou subclasse indireta de uma classe de reflexão. Como o nome sugere, getSuperclass() é obter a classe pai de uma classe de reflexão.
A classe pública TypeCounter estende o hashmap <classe <?>, Integer> {classe privada <?> Basetype; public Typecounter (classe <?> Basetype) {this.BaseType = Basetype; } public void count (object obj) {class <?> type = obj.getclass (); if (! BASETYPE.ISASSIGNABLEFROM (TYPE)) {THRON NOVA RUNTIMEEXCECTION (OBJ + "TIPO INCORRETO" + TIPO + ", deve ser o tipo ou subtipo de" + BaseType); } countclass (tipo); } private void countclass (classe <?> type) {quantidade inteira de quantidade = get (type); put (tipo, quantidade == null? 1: quantidade + 1); Classe <?> Superclass = type.getSuperclass (); if (superclass! = null && basetype.isassignablefrom (superclass)) {countclass (superclass); }} @Override public string tostring () {stringbuilder resultado = new StringBuilder ("{"); para (map.entry <classe <?>, Integer> par: entradas ()) {result.append (par.getKey (). getSImpleName ()); resultado.Append ("="); resultado.Append (par.getValue ()); resultado.Append (","); } resultado.Delete (resultado.Length () - 2, resultado.Length ()); resultado.Append ("}"); return resultado.toString (); }}Resumir
O exposto acima é todo o conteúdo deste artigo sobre o compartilhamento de código de exemplo do mecanismo de reflexão Java, e espero que seja útil para todos. Amigos interessados podem continuar se referindo a este site:
Java Programação e Impressão de Compras Código de Implementação de Compras
Explicação detalhada da implementação de referências e proxy dinâmico em Java
Programação Java para implementar o compartilhamento de código simples do eclipse lunar
Se houver alguma falha, deixe uma mensagem para apontá -la. Obrigado amigos pelo seu apoio para este site!