Exploration of array reflection in java
What is the use of array reflection? When should we use array reflection? Let's take a look at the following code:
Integer [] nums = {1, 2, 3, 4}; Object [] objs = nums; // here Integer [] can be automatically converted to Object [] Object obj = nums; // Integer [] is of course an Objectint [] ids = {1, 2, 3, 4}; // Object [] objs2 = ids; // int [] cannot be converted to Object [] Object obj2 = ids here; // int [] is an Object
The preceding example shows that a basic type of one-dimensional array can only be used as an Object rather than an Object [].
Int [] [] intArray = {1, 2}, {3, 4}; Object [] oa = intArray; Object obj = intArray; // Integer [] [] integerArray = intArray; int [] [] not Integer [] [] Integer [] [] integerArray2 = new Integer [] [] {1, 2 },{ 3, 4 }}; Object [] [] oa2 = integerArray2; Object [] oa3 = integerArray2; Object obj2 = integerArray2;
From the above example, we can see that the two arrays in java are arrays. The following is an example of array reflection:
Package cn. zq. array. reflect; import java. lang. reflect. array; import java. util. arrays; import java. util. random; public class ArrayReflect {public static void main (String [] args) {Random rand = new Random (47); int [] is = new 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);/* The two outputs above all output strings similar to [[I @ 14318bb]. The content in the Array Memory cannot be displayed, of course, we use traversal to output the content in the array */System. out. println (-- 1. print the array by traversing the array in the conventional way --); for (int I = 0; I <is. length; I ++) {System. out. print (is [I] +);} System. out. println (); System. out. println (-- 2. print the array by traversing the array through array reflection --); Object obj = is; // convert the one-dimensional int array to the Object System. out. println (obj isArray: + obj. getClass (). isArray (); for (int I = 0; I <Array. getLength (obj); I ++) {int num = Array. getInt (obj, I); // you can also use this common method to obtain the value of the corresponding index position // Object value = Array. get (obj, I); // If the array stores the basic type, the returned value is the packaging type System corresponding to the basic type. out. print (num + );}}}
Output:
[I @ 14318bb [[I @ 14318bb] -- 1. print the array in the regular way -- 58 55 93 61 61 29 68 0 22 7 -- 2. print the array by traversing the array through array reflection -- obj isArray: true58 55 93 61 61 29 68 0 22 7
In the preceding example, a one-dimensional array of int is created, and the random image is filled with 0 ~ The integer of 100. Then, the array is output directly using the System. out. println () method or the Arrays. asList method (
If it is not a basic type of one-dimensional array, this method can be converted to List as expected. If it is a two-dimensional array, it cannot be converted to List as expected.) Convert the array into a List and then output it. The result is not the expected output. Next, we output the content in the array in the way of regular array traversal. Then we regard int [] as an Object and use reflection to traverse its content. Class. isArray () can be used to determine whether an object is an array. If it is an array. lang. reflect. the Array tool class for Array reflection to obtain information about the Array. This class uses some get methods to obtain the length of the Array, each version is used to obtain the index value of a basic type of one-dimensional array. The general method for getting the value is get (Object array, int index), and the method for setting the value, there are two other methods to create an array instance. Through the array reflection tool class, you can easily use array reflection to write common code without having to determine whether the given array is a basic type of array.
package cn.zq.array.reflect;import java.lang.reflect.Array;public class 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);Object 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 = 20iss.length = 10, iss[0].lenght = 8
Array uses two methods to create an Array.
Object newInstance (Class ComponentType, int length), creates an array with a specified length based on the provided class, if int is provided as above. class, which is 10 in length, equivalent to new int [10]; Object newInstance (Class ComponentType, int... dimensions), creates an Array Based on the provided class and dimension. The dimensions variable parameter is used to specify the length of each dimension of the array, as in the preceding example, a two-dimensional array with a new int [10] [8] is created, but a multi-dimensional array with different lengths cannot be created. By using the first method to create an Array, you can create an Array Object o = Array like this. newInstance (int []. class, 20) can be used to create a two-dimensional array, which is equivalent to Object o = new int [20] [];
Of course, using the example above to create an array is rare and redundant. Why not directly use new to create an array? Creating arrays through reflection is not as fast as new, but the writing program is not easy to read. It is not as direct as new. In fact, it is rare to create an array through reflection. What kind of abnormal requirements do we need to use reflection to create an array!
As there are some obstacles to output basic types of arrays, we will use array reflection to implement a tool class to achieve the expected output:
Package 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);} public static PrintStream format (String format, Object... objects) {return format (System. out, format, objects);} public static PrintStream format (PrintStream out, String format, Object... objects) {Object [] handleObjects = new Object [objects. length]; f Or (int I = 0; I <objects. length; I ++) {Object object = objects [I]; if (object = null | isPrimitiveWrapper (object) {handleObjects [I] = object ;} else {ByteArrayOutputStream bos = new ByteArrayOutputStream (); PrintStream ps = new PrintStream (bos); printnb (object, ps); ps. close (); handleObjects [I] = new String (bos. toByteArray ();} out. format (format, handleObjects); return out;}/*** determine whether a given object is a basic packaging class. * @ Param o the given Object * @ return if it is a basic type of packaging class, yes is returned; otherwise, no is returned. */Private static boolean isPrimitiveWrapper (Object o) {return o instanceof Void | o instanceof Boolean | o instanceof Character | o instanceof bytes | o instanceof Short | o instanceof Integer | o instanceof Long | o instanceof Float | o instanceof Double ;} 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 ++) {Object value = Array. get (obj, I); result. append (getPrintString (value); if (I! = Len-1) {result. append (,) ;}} result. append (]);} else {result. append (String. valueOf (obj);} return result. toString ();}}
The Print tool class above provides some practical static methods for output, and provides some overloaded versions. You can compile some overloaded versions as you like, you can Print basic types of one-dimensional arrays and multi-dimensional arrays. See the following example of the Print tool for testing:
Package cn. zq. array. reflect; import static cn. zq. util. print. print; import java. io. printStream; import static cn. zq. util. print. *; public class PrintTest {static class Person {private static int counter; private final int id = counter ++; public String toString () {return getClass (). getSimpleName () + id ;}} public static void main (String [] args) throws Exception {print (-- print non-array --); print (new Object ()); print (-- print Print a one-dimensional array of the basic type --); int [] is = new int [] {1, 22, 31, 44, 21, 33, 65}; print (is ); print (-- print a two-dimensional array of the basic type --); int [] [] iss = new int [] [] {11, 12, 13, 14}, {21, 22 ,}, {31, 32, 33 }}; print (iss); print (-- print a non-basic one-dimensional array --); person [] persons = new Person [10]; for (int I = 0; I <persons. length; I ++) {persons [I] = new Person ();} print (persons); print (-- print a two-dimensional array of non-basic types --); person [] [] persons2 = new Person [] [] {new Person ()}, {new Perso N (), new Person ()}, {new Person (),},}; print (persons2 ); print (-- print empty array --); print (new int [] {}); print (-- print an array containing null values --); object [] objects = new Object [] {new Person (), null, new Object (), new Integer (100)}; print (objects ); print (-- print a two-dimensional array in special cases --); Object [] [] objects2 = new Object [3] []; objects2 [0] = new Object [] {}; objects2 [2] = objects; print (objects2); print (-- output the results of a one-dimensional array to the file --); Pri NtStream out = new PrintStream (out. c); try {print (iss, out);} finally {out. close () ;}print (-- format output --); format (%-6d % s % B % s, 10086, is, true, iss ); /*** some common methods of the Print tool class are listed above. * There are some unlisted methods. Please check them yourself. */}}
Output:
-- Print non-array -- java. lang. object @ 61de33 -- print a one-dimensional array of the basic type -- [1, 22, 31, 44, 21, 33, 65] -- print a two-dimensional array of the basic type -- [[11, 12, 13, 14], [21, 22], [31, 32, 33] -- print a non-basic one-dimensional array -- [Person0, Person1, Person2, Person3, Person4, person5, Person6, Person7, Person8, Person9] -- print a non-basic two-dimensional array -- [[Person10], [Person11, Person12], [Person13, Person14, person15] -- print the empty array -- [] -- print the array containing null values -- [Person16, null, java. lang. object @ ca0b6, 100] -- print a two-dimensional array in special cases -- [[], null, [Person16, null, java. lang. object @ ca0b6, 100] -- output the result of a one-dimensional array to a file ---- formatted output -- 10086 is TRUE [[11, 12, 13, 14], [21, 22], [31, 32, 33]
Output file:
It can be seen that the Print tool class has the ability to Print basic types of one-dimensional arrays and multi-dimensional arrays. In general, the tool class above is quite practical, to avoid manual code writing every time you want to view the content in the array, it is too troublesome. In the future, you can simply use the Print tool class, how convenient it is.
The tool class above can work very well, but if you have such a requirement: Give you an array (or another container), you can give me a whole List. So what should we do? In fact, Arrays. asList does not always get the expected results. Although Java 5 has added generics, It is limited and cannot be as common as c ++ templates, it is precisely because there is a basic type in java. Even if there is an automatic packaging mechanism, it cannot be used together with generics. The parameter type must be a certain type, rather than a basic type. Here is a solution:
Package cn. zq. util; import java. lang. reflect. array; import java. util. arrayList; import java. util. arrays; import java. util. enumeration; import java. util. iterator; import java. util. list; import java. util. map; public class CollectionUtils {public static List
AsList (Object obj) {return convertToList (makeIterator (obj);} public static
List
ConvertToList (Iterator
Iterator) {if (iterator = null) {return null;} List
List = new ArrayList
(); While (iterator. hasNext () {list. add (iterator. next ();} return list ;}@ SuppressWarnings ({rawtypes, unchecked}) public static Iterator
MakeIterator (Object obj) {if (obj instanceof Iterator) {return (Iterator
) Obj;} if (obj = null) {return null;} if (obj instanceof Map) {obj = (Map
) Obj). entrySet ();} Iterator
Iterator = null; if (obj instanceof Iterable) {iterator = (Iterable
) Obj ). iterator ();} else if (obj. getClass (). isArray () {// Object [] objs = (Object []) obj; // an Array of the original type cannot be converted to ArrayList list = 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 instanceof Enumeration) {iterator = new EnumerationIterator (Enumeration) obj);} else {iterator = Arrays. asList (obj ). iterator ();} return iterator;} public static class EnumerationIterator
Implements Iterator
{Private Enumeration
Enumeration; public EnumerationIterator (Enumeration
Enumeration) {this. enumeration = enumeration;} public boolean hasNext () {return enumeration. hasMoreElements ();} public T next () {return enumeration. nextElement ();} public void remove () {throw new UnsupportedOperationException ();}}}
Test code:
Package 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 (-- basic type, one-dimensional array --); int [] nums = {1, 3, 5, 7, 9}; List
List = CollectionUtils. asList (nums); System. out. println (list); System. out. println (-- non-basic type, one-dimensional array --); Person [] persons = new Person [] {new Person (),}; List
PersonList = (List
) CollectionUtils. asList (persons); System. out. println (personList); System. out. println (-- Iterator --); Iterator
Iterator = personList. iterator (); List
PersonList2 = (List
) CollectionUtils. asList (iterator); System. out. println (personList2 );}}
Output:
-- Basic Type One-dimensional array -- [1, 3, 5, 7, 9] -- non-basic type one-dimensional array -- [Person0, Person1, Person2] -- Iterator -- [Person0, Person1, person2]
The java container class library can be divided into Collection, Map, array, and Iterator (and earlier legacy interface Enumeration) is a common interface of all containers and the Collection interface is from Iterable (the iterator of this interface will return an Iterator). Therefore, these situations are processed one by one in the makeIterator method and Map type is implemented, you only need to call its entrySet () method. For classes that implement the Iterable interface (including Collection), call iterator () to directly obtain the Iterator object. For Enumeration type, use the adapter EnumerationIterator for adaptation. For Arrays, use array reflection to traverse Arrays and put them into ArrayList. For other types, call Arrays. the asList () method creates a List. CollectionUtils also provides some other methods for conversion. You can add the required methods as needed.
Summary: array reflection provides more convenient and flexible methods for designs that may contain arrays, so as not to write complicated judgment statements. This flexibility costs performance, it is really not necessary to use array reflection when there is no need for Array reflection at all. Whether to use array reflection. In actual development, you can choose whether to use array reflection based on your needs. The best way is to use practice to explore the path, first, write in the way you think, and constantly improve in practice.