Que es la reflexión
"La reflexión permite que los programas se ejecuten en el JVM detectar y modificar el comportamiento del tiempo de ejecución". Este concepto a menudo se confunde con la introspección. Aquí están las explicaciones de estos dos términos en Wikipedia:
Ejemplo de introspección: la instancia del operador se usa para detectar si un objeto pertenece a una clase específica.
if (obj instancia de perro) {perro d = (perro) obj; D.Bark ();}Ejemplo de reflexión: el método class.forname () puede obtener el objeto de clase correspondiente a través del nombre de la clase o interfaz (una cadena o nombre totalmente calificado). El método de Forname desencadena la inicialización de la clase.
// use la clase de reflexión <?> C = class.forname ("classpath.and.classname"); object dog = c.newinstance (); método m = c.getDeclaredMethod ("ladrido", nueva clase <?> [0]); m.invoke (perro);En Java, la reflexión está más cerca de la introspección porque no puede cambiar la estructura de un objeto. Aunque se pueden usar algunas API para modificar la visibilidad de los métodos y propiedades, no pueden modificar las estructuras.
Reflejo de matrices
¿Cuál es el uso del reflejo de una matriz? ¿Cuándo necesitas usar el reflejo de las matrices? Echemos un vistazo al siguiente código:
Entero [] nums = {1, 2, 3, 4}; Objeto [] objs = nums; // se puede convertir automáticamente en entero [] a objeto [] object obj = nums; // Integer [] es, por supuesto, un objeto int [] ids = {1, 2, 3, 4}; // objeto [] objs2 = ids; // El int [] no se puede convertir en objeto [] objero obj2 = ids; // int [] es un objetoEl ejemplo anterior muestra que un tipo básico de matriz unidimensional solo puede considerarse como un objeto, no como un objeto [].
int [] [] intarray = {{1, 2}, {3, 4}}; Objeto [] OA = Intarray; Object obj = intarray; // integer [] [] integerArray = entarray; int [] [] no entero [] [] integer [] [] integerarray2 = new Integer [] [] {{1, 2}, {3, 4}}; Objeto [] [] OA2 = IntegerArray2; Objeto [] oa3 = integerArray2; Objeto obj2 = integerArray2;Del ejemplo anterior, podemos ver que la matriz de dos dígitos de Java es una matriz de matrices. Echemos un vistazo al ejemplo de reflejar una matriz:
paquete cn.zq.array.reflect; import java.lang.reflect.array; importar java.util.arrays; import java.util.random; Public Class ArrayReflect {public static void main (String [] args) {Random Rand = new Random (47); int [] es = nuevo int [10]; for (int i = 0; i <is.length; i ++) {is [i] = rand.nextint (100); } System.out.println (is); System.out.println (arrays.aslist (is)); /*Las dos salidas anteriores son cadenas similares a "[[i@14318bb]", que no puede mostrar el contenido almacenado en la matriz. Por supuesto, usamos el recorrido para producir el contenido en la matriz*/ system.out.println ("-1. Traversal a la matriz imprimiendo-"); for (int i = 0; i <is.length; i ++) {system.out.print (es [i]+""); } System.out.println (); System.out.println ("-2. Traversal a la matriz imprimiendo-"); Obj obj = is; // Convertir la matriz int unidimensional a objeto System.out.println ("obj isArray:" + obj.getClass (). IsArray ()); for (int i = 0; i <array.getLength (obj); i ++) {int num = array.getInt (obj, i); // También puede usar este método de uso común para obtener el valor de la posición de índice correspondiente // valor de objeto = array.get (obj, i); // Si la matriz almacena el tipo básico, entonces el tipo de envoltura correspondiente al tipo básico System.out.print (num + ""); }}}Producción:
[I@14318BB [[i@14318bb] ---1. Imprima la matriz atravesando la matriz por medios convencionales: 58 55 93 61 61 29 68 0 22 7 --2. Imprima la matriz atravesando la matriz atravesando la matriz atravesando la matriz.
El ejemplo anterior primero crea una matriz unidimensional de INT, y luego llena aleatoriamente un entero de 0 ~ 100. Luego, salga directamente la matriz a través del método System.out.println () o use el método matrices. La matriz se convierte en la lista y luego la salida, y el paso no es el resultado de salida que esperamos. A continuación, los contenidos en la matriz se emiten en un método transversal de matriz regular y luego tratan int [] como un objeto, y usa la reflexión para atravesar su contenido. Class.IsArray () se puede usar para determinar si un objeto es una matriz. Si es una matriz, entonces la información relevante de la matriz se obtiene a través de Java.lang.Reflect.Array, una clase de herramientas que refleja la matriz. Esta clase utiliza algunos métodos GET para obtener la longitud de la matriz, cada versión se utiliza para obtener el índice correspondiente de la matriz unidimensional de tipos básicos, un método general para obtener el valor (matriz de objetos, INT índice), un método para establecer el valor y dos métodos para crear instancias de matriz. A través de la clase de herramientas de reflexión de matriz, es fácil usar la reflexión de la matriz para escribir código general sin tener que juzgar qué tipo de matriz básica es la matriz dada.
paquete cn.zq.array.reflect; import java.lang.reflect.array; clase pública NewArrayInstance {public static void main (string [] args) {object o = array.newinstance (int.class, 20); int [] is = (int []) o; System.out.println ("is.length =" + is.length); Objeto o2 = array.newinstance (int.class, 10, 8); int [] [] iss = (int [] []) o2; System.out.println ("iss.length =" + iss.length + ", iss [0] .lenght =" + iss [0] .length); }} is.length = 20 iss.length = 10, iss [0] .lenght = 8 La matriz ha pasado 2 métodos para crear una matriz
Object NewInstance (clase <?> ComponentType, int longitud), cree una matriz de longitud especificada basada en la clase proporcionada. Si int.class se proporciona como arriba, la longitud es 10, que es equivalente a nuevo int [10];
Object NewInstance (clase <?> ComponentType, int ... dimensiones), crea una matriz basada en la clase y las dimensiones proporcionadas. Las dimensiones de parámetros variables se utilizan para especificar la longitud de cada dimensión de la matriz. Como en el ejemplo anterior, es equivalente a crear una matriz bidimensional de nuevo int [10] [8], pero no puede crear una matriz multidimensional con diferentes longitudes de cada dimensión. A través del primer método para crear una matriz, puede crear una matriz como esta. Objeto o = array.newinstance (int []. Clase, 20) se puede usar para crear una matriz bidimensional, que es equivalente a objeto o = nuevo int [20] [];
Por supuesto, es raro usar el ejemplo anterior para crear una matriz, pero en realidad es redundante. ¿Por qué no crear una matriz directamente a través de nuevo? La reflexión crea una matriz no solo más rápida que la nueva, sino que también el programa escrito no es fácil de leer, por lo que no es tan directo como nuevo. De hecho, es realmente raro crear matrices a través de la reflexión. ¡Qué tipo de necesidades anormales hay para usar la reflexión para crear matrices!
Dado que se encontraron algunos obstáculos al emitir una matriz de tipos básicos, lo siguiente utilizará la reflexión de la matriz para implementar una clase de herramienta para lograr la salida deseada:
paquete cn.zq.util; import java.io.bytearrayOutputStream; import java.io.printstream; import java.lang.reflect.array; Public Class Print {public static void print (object obj) {print (obj, system.out); } Public static void print (object obj, printStream out) {out.println (getPrintString (obj)); } public static void println () {print (system.out); } public static void println (printStream out) {out.println (); } public static void printnb (object obj) {printnb (obj, system.out); } public static void printnb (object obj, printStream out) {out.print (getPrintString (obj)); } Format de impresión estatica pública (formato de cadena, objeto ... objetos) {Formato de retorno (System.out, Format, Objects); } Formato de impresión estatica pública (printStream Out, String Format, Object ... Objects) {Object [] HandleObjects = new Object [Objects.Length]; for (int i = 0; i <objects.length; i ++) {object object = objets [i]; if (object == null || isPrimitiveWrapper (object)) {handleObjects [i] = object; } else {byteArRaReOutputStream bos = new ByteArRaReOutputStream (); PrintStream PS = new PrintStream (BOS); printnb (objeto, ps); ps.close (); handleObjects [i] = new String (bos.tobytearray ()); }} out.Format (formato, handleObjects); regresar; } /*** Determine si un objeto dado es una clase de envoltura del tipo básico. * @param o objeto de objeto dado * @return Si es una clase de envoltura de tipos primitivos, devuelve sí, de lo contrario, devuelva el número */ privado static boolean isPrimitiveWrapper (objeto o) {return o instancia de void || o instancia de booleano || o instancia de carácter || o instancia de byte || o Instancia de breve || o instancia de entero || o instancia de largo || o instancia de flotación || o instancia de doble; } public static string getPrintString (object obj) {stringBuilder result = new StringBuilder (); if (obj! = null && obj.getClass (). isarray ()) {result.append ("["); int len = array.getLength (obj); for (int i = 0; i <len; i ++) {objeto valor = array.get (obj, i); resultado.append (getPrintString (valor)); if (i! = len - 1) {result.append (","); }} result.append ("]"); } else {result.append (string.ValueOf (obj)); } return resultado.toString (); }}La clase de herramienta de impresión anterior proporciona algunos métodos estáticos prácticos para la salida y proporciona algunas versiones sobrecargadas. Puede escribir algunas versiones sobrecargadas basadas en sus preferencias personales, lo que respalda la impresión de tipos básicos de matrices unidimensionales y matrices multidimensionales. Consulte los siguientes ejemplos de la prueba de la herramienta de impresión:
paquete cn.zq.array.reflect; import static cn.zq.util.print.print; import java.io.printstream; import static cn.zq.util.print.*; Public Class PrintTest {Persona de clase estática {contador privado static int; Private final int id = contador ++; public String toString () {return getClass (). getSimpLename () + id; }} public static void main (string [] args) lanza la excepción {imprime ("-imprime sin array--"); imprimir (nuevo objeto ()); imprimir ("-Imprimir una matriz unidimensional de tipos básicos--"); int [] is = new int [] {1, 22, 31, 44, 21, 33, 65}; imprimir (is); imprimir ("-Imprimir matriz bidimensional de tipos básicos--"); int [] [] iss = new int [] [] {{11, 12, 13, 14}, {21, 22,}, {31, 32, 33}}; imprimir (ISS); imprimir ("-Imprimir matriz unidimensional de tipos no base--"); Persona [] personas = nueva persona [10]; para (int i = 0; i <personas.length; i ++) {personas [i] = new Person (); } imprimir (personas); imprimir (personas); imprimir ("-Imprima una matriz bidimensional de tipos no ejercicios--"); Persona [] [] personas2 = nueva persona [] [] {{nueva persona ()}, {nueva persona (), nueva persona ()}, {nueva persona (), nueva persona (), nueva persona (), nueva persona (),},}; imprimir (personas2); imprime ("-imprima una matriz vacía--"); print (new int [] {}); imprimir ("-Imprimir una matriz con valores nulos--"); Object [] Objects = new Object [] {New Person (), NULL, New Object (), New Integer (100)}; imprimir (objetos); imprimir ("-Imprimir una matriz bidimensional para casos especiales--"); Objeto [] [] objetos2 = nuevo objeto [3] []; Objects2 [0] = nuevo objeto [] {}; objetos2 [2] = objetos; imprimir (objetos2); imprimir ("-emitir el resultado de la matriz unidimensional al archivo--"); PrintStream out = new printStream ("out.c"); intente {print (iss, out); } finalmente {out.close (); } print ("-salida de formato--"); formato (" %-6d %s %b %s", 10086, "es", verdadero, ISS); /** * Algunos métodos comúnmente utilizados de clases de herramientas de impresión se enumeran anteriormente, * También hay algunos métodos no listados, verifíquelo usted mismo. */}} Producción:
--Print no array-java.lang.object@61de33-imprenta matriz unidimensional de tipos básicos-[1, 22, 31, 44, 21, 33, 65]-imprenta matriz bidimensional de tipos básicos-[[11, 12, 13, 14], [21, 22], [31, 32, 33]]-unas básicas de no-dimensional de no-base-type- Person1, persona2, persona3, persona4, persona5, persona6, persona7, persona8, persona9]-huella matriz bidimensional de tipo no base-[[persona10], [persona11, persona12], [persona13, persona14, persona15]]-imprenta la matriz vacía-[]-hintinga con valores nulos-[persona16, null, java.lang.object 100b6, 100b6, introduce los valores nulos-[Person16, nullo, java.lang.object. -huella matriz bidimensional en casos especiales-[[], nulo, [Person16, NULL, java.lang.object@ca0b6, 100]] --print El resultado de la matriz unidimensional a un archivo--La salida de formato-10086 es verdadero [[11, 12, 13, 14], [21, 22], [31, 32, 33]]
Archivo de salida:
Se puede ver que la clase de herramienta de impresión ya tiene la capacidad de imprimir tipos básicos de matrices unidimensionales y matrices multidimensionales. En términos generales, la clase de herramientas anterior es bastante práctica, para no escribir código manualmente cada vez que desee ver el contenido en la matriz. Eso sería demasiado problemático. Simplemente use la clase de herramientas de impresión en el futuro. Que conveniente.
La clase de herramientas anterior funciona muy bien, pero si hay un requisito: darle una matriz (y tal vez otros contenedores), puede crear una lista para mí. Entonces, ¿qué debemos hacer? De hecho, Arrays.aslist no siempre obtiene los resultados que esperamos. Aunque Java5 agrega genéricos, tiene limitaciones y no puede ser tan general como las plantillas de C ++. Es precisamente porque hay tipos básicos en Java. Incluso si hay un mecanismo de envoltura automática, no se puede usar con genéricos. El tipo de parámetro debe ser de cierto tipo, no un tipo básico. Aquí hay una solución para la suya:
paquete cn.zq.util; import java.lang.reflect.array; import java.util.arrayList; importar java.util.arrays; importar java.util.enerumeration; import java.util.iterator; import java.util.list; import java.util.map; Public ClassUtils {public static list <?> Aslist (object obj) {return ConvertTolist (MakEiterator (obj)); } public static <t> list <t> converttolist (iterator <t> iterator) {if (iterator == null) {return null; } List <t> list = new ArrayList <T> (); while (iterator.hasnext ()) {list.add (iterator.next ()); } Lista de retorno; } @SupplesSwarnings ({"RawTypes", "sin verificar"}) público estático iterador <?> MakIterator (object obj) {if (obj instanceOf iterator) {return (iterator <?>) Obj; } if (obj == null) {return null; } if (obj instanciaf map) {obj = ((map <?,?>) obj) .EntrySet (); } Iterator <?> Iterator = null; if (obj instancia de iterable) {iterator = ((iterable <?>) obj) .Iterator (); } else if (obj.getClass (). isarray ()) {// object [] objs = (object []) obj; // o las matrices de tipos primitivos no se pueden convertir como esta lista ArrayList = new ArrayList (array.getLength (obj)); for (int i = 0; i <array.getLength (obj); i ++) {list.add (array.get (obj, i)); } iterator = list.iterator (); } else if (obj instancia de enumeración) {iterator = new EnumerationIterator ((enumeración) obj); } else {iterator = arrays.aslist (obj) .Iterator (); } return iterator; } Public static class EnumerationIterator <T> implementa Iterator <T> {enumeración privada <t> enumeración; enumeración pública (enumeración <t> enumeración) {this.enumeration = enumeration; } public boolean HasNext () {return enumeration.hasmoreElements (); } public t next () {return enumeration.nextelement (); } public void remove () {lanzar nueva UnpportedOperationException (); }}}Código de prueba:
paquete cn.zq.array.reflect; import java.util.iterator; import java.util.list; import cn.zq.array.reflect.printtest.person; import cn.zq.util.CollectionUtils; public class CollectionUtilStest {public static void main (String [] args) {System.out.println ("--- Tipo básico matriz unidimensional--"); int [] nums = {1, 3, 5, 7, 9}; List <?> List = collectionUtils.aslist (nums); System.out.println (lista); System.out.println ("-no básico matriz unidimensional--"); Persona [] personas = nueva persona [] {nueva persona (), nueva persona (), nueva persona (),}; Lista <Oll> PersonList = (List <OlPER>) COLLEdUtils.aslist (Personas); System.out.println (Personlist); System.out.println (Personlist); System.out.println ("-iterator--"); Iterador <Oll> iterator = PersonList.Iterator (); Lista <Oll> PersonList2 = (List <Oll>) CollectionUtils.aslist (iterator); System.out.println (Personlist2); }}Producción:
-matriz unidimensional de tipo básico-- [1, 3, 5, 7, 9]-no básica matriz unidimensional-- [Person0, persona1, persona2] --Iterator-- [Person0, Person1, Person2]
En la biblioteca de la clase de contenedores Java, se puede dividir en colección, mapa y matriz. Dado que el iterador (y la enumeración temprana de la interfaz heredada) es la interfaz general de todos los contenedores y la interfaz de colección proviene de ITerable (el iterador de esta interfaz devolverá un iterador), estas situaciones se procesan una por una en el método de MakIterator. Para los tipos de mapas, solo se debe llamar al método EntrySet (). Para las clases que implementan la interfaz iterable (incluida la colección), llame a Iterator () para obtener directamente el objeto Iterator. Para los tipos de enumeración, use el adaptador EnumerationIterator para la adaptación. Para matrices, use la reflexión de la matriz para atravesar la matriz en ArrayList y llame al método matrices.aslist () para crear una lista para otros tipos. CollectUtils también proporciona otros métodos para convertir, y puede agregar los métodos que necesita según sea necesario.
Resumen: La reflexión de la matriz proporciona métodos más convenientes y flexibles para diseños donde pueden aparecer matrices, para no escribir declaraciones de juicio más problemáticas. Esta flexibilidad paga el precio del rendimiento, y realmente no es necesario usar la reflexión de la matriz cuando no se necesita la reflexión de la matriz. Si usar reflexiones de matriz es diferente en el desarrollo real. Elija si usar reflexiones de matriz de acuerdo con las necesidades. La mejor manera es explorar el camino a través de la práctica, escribir en la forma en que piensa y mejorar constantemente en la práctica.