Что такое отражение
«Отражение позволяет программам, работающим в JVM, обнаруживать и изменять поведение времени выполнения». Эта концепция часто путается с самоанализом. Вот объяснения этих двух терминов в Википедии:
Пример самоанализа: экземпляр оператора используется для определения того, принадлежит ли объект конкретному классу.
if (obj exantyof dog) {dog d = (собака) obj; d.bark ();}Пример отражения: метод class.forname () может получить соответствующий объект класса через имя класса или интерфейса (строка или полностью квалифицированное имя). Метод ForName запускает инициализацию класса.
// Использовать класс отражения <?> C = class.forname ("classpath.and.classname"); Object Dog = c.newinstance (); метод m = c.getdeclaredmethod ("bark", новый класс <?> [0]); m.invoke (dog);В Java отражение ближе к самоанализу, потому что вы не можете изменить структуру объекта. Хотя некоторые API могут использоваться для изменения видимости методов и свойств, они не могут изменять структуры.
Отражение массивов
Каково использование отражения массива? Когда вам нужно использовать отражение массивов? Давайте посмотрим на следующий код:
Integer [] nums = {1, 2, 3, 4}; Object [] objs = nums; // может быть автоматически преобразован в целое число [] в объект [] объект obj = nums; // Integer [], конечно, объект int [] ids = {1, 2, 3, 4}; // объект [] objs2 = ids; // int [] не может быть преобразован в объект [] объект obj2 = ids; // int [] является объектомПриведенный выше пример показывает, что основной тип одномерного массива можно рассматривать только как объект, а не как объект [].
int [] [] intarray = {{1, 2}, {3, 4}}; Object [] oa = intarray; Объект obj = intarray; // integer [] [] integerarray = intarray; int [] [] not integer [] [] integer [] [] integerarray2 = new Integer [] [] {{1, 2}, {3, 4}}; Object [] [] oa2 = integerarray2; Object [] oa3 = integerarray2; Объект obj2 = integerarray2;Из приведенного выше примера мы видим, что двухзначный массив Java представляет собой массив массивов. Давайте посмотрим на пример отражения массива:
Пакет cn.zq.array.reflect; импортировать java.lang.reflect.array; импортировать java.util.arrays; импортировать java.util.random; открытый класс ArrayReflect {public static void main (string [] args) {случайный 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)); /*Приведенные выше два выхода представляют собой строки, похожие на «[[i@14318bb]», которые не могут отображать контент, хранящийся в массиве. Конечно, мы используем Traversal для вывода содержимого в массиве*/ system.out.println ("-1. Траверная массива путем печати-"); for (int i = 0; i <is.length; i ++) {System.out.print (is [i]+""); } System.out.println (); System.out.println ("-2. Traversal в массив путем печати-"); Объект obj = is; // преобразовать одномерный массив int в объектные системы. for (int i = 0; i <array.getLength (obj); i ++) {int num = array.getint (obj, i); // Вы также можете использовать этот обычно используемый метод для получения значения соответствующего положения индекса // значение объекта = Array.get (obj, i); // Если массив хранит основной тип, то тип обертки, соответствующий System Basic Type.out.print (num + ""); }}}Выход:
[I@14318bb [[i@14318bb] - -1. Распечатайте массив, пройдя массив обычным средством-58 55 93 61 61 29 68 0 22 7 --2. Распечатайте массив, пройдя массив, пройдя массив, пройдя массив- obj isarray: true 58 55 93 61 61 29 68 0 22 7
Приведенный выше пример сначала создает одномерный массив Int, а затем случайным образом заполняет целое число 0 ~ 100. Затем, непосредственно выводит массив через метод System.out.println () или используйте метод Arrays.aslist (если он не является одномерным массивом основных типов, этот метод может быть преобразован для перечисления, как и ожидалось, и если это двумерная массива, его нельзя преобразовать, чтобы перечислить, как мы ожидаем). Массив преобразуется в список, а затем выводит, а прохождение не является результатом выходного сигнала, который мы ожидаем. Затем содержимое в массиве выводится в обычном методе обхода массива, а затем обрабатывают int [] как объект, и используют отражение для пересечения его содержания. Class.isarray () может использоваться для определения того, является ли объект массивом. Если это массив, то соответствующая информация массива получается через java.lang.reflect.array, класс инструментов, который отражает массив. В этом классе используются некоторые методы GET для получения длины массива, каждая версия которой используется для получения соответствующего индекса одномерного массива основных типов, общего метода для получения значения (массив объектов, индекс Int), метода для установки значения и двух методов для создания экземпляров массива. Благодаря классу инструментов для рефлексии массива легко использовать рефлексию массива для написания общего кода без необходимости судить, какой основной тип массива является данным массивом.
Пакет cn.zq.array.reflect; импортировать java.lang.reflect.array; открытый класс 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); Объект 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 Массив прошел 2 метода для создания массива
Object NewInstance (класс <?> ComponentType, int Length), создайте массив указанной длины на основе предоставленного класса. Если int.class предоставляется, как указано выше, длина составляет 10, что эквивалентно новому int [10];
Object newInstance (класс <?> ComponentType, int ... Размеры), создает массив на основе предоставленного класса и размеров. Размеры переменных параметров используются для указания длины каждого измерения массива. Как и в приведенном выше примере, он эквивалентен созданию двумерного массива нового int [10] [8], но не может создать многомерный массив с различной длиной каждого измерения. С помощью первого метода создания массива вы можете создать такой массив. Object O = Array.NewinStance (int []. Class, 20) может использоваться для создания двухмерного массива, который эквивалентен объекту O = новый int [20] [];
Конечно, редко можно использовать приведенный выше пример для создания массива, но на самом деле он избыточно. Почему бы не создать массив непосредственно через новый? Reflection создает массив не только быстрее, чем новая, но и написанная программа нелегко читать, поэтому он не такой прямой, как новый. На самом деле, это действительно редко создавать массивы с помощью отражения. Какие ненормальные потребности существуют, чтобы использовать отражение для создания массивов!
Поскольку некоторые препятствия были столкнулись при выводе массива основных типов, следующее будет использовать отражение массива для реализации класса инструментов для достижения желаемого вывода:
Пакет cn.zq.util; импортировать java.io.bytearrayoutputstream; Импорт java.io.printstream; импортировать 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 (строка формат, объект ... объекты) {return format (System.out, format, Objects); } public Static PrintStream Format (PrintStream Out, String Format, Object ... Objects) {Object [] handleObjects = new Object [Objects.length]; for (int i = 0; i <objects.length; i ++) {object object = object [i]; if (object == null || isprimitiationwrapper (object)) {handleobjects [i] = object; } else {bytearrayOutputStream bos = new BytearRayOutputStream (); PrintStream PS = новый PrintStream (BOS); printnb (объект, ps); ps.close (); handleobjects [i] = new String (bos.tobytearray ()); }} out.format (format, handleobjects); вернуться; } /*** Определите, является ли заданный объект классом обертки основного типа. * @param o Указанный объект объекта * @return, если это обертка класса примитивных типов, возвращайте Да, иначе вернуть № */ private static boolean isprimitywrapper (Object o) {return o ancementof void || o экземпляр логического || o Экземпляр символа || o экземпляр байта || o экземпляр коротких || o экземпляр целого числа || o экземпляр длинного || o Экземпляр Float || o экземпляр двойного; } 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 (значение)); if (i! = len - 1) {result.append (","); }} result.append ("]"); } else {result.append (string.valueof (obj)); } return result.toString (); }}Приведенный выше класс печати предоставляет некоторые практические статические методы для вывода и предоставляют несколько перегруженных версий. Вы можете написать несколько перегруженных версий на основе ваших личных предпочтений, поддерживая печать основных типов одномерных массивов и многомерных массивов. См. Следующие примеры тестирования инструмента печати:
Пакет cn.zq.array.reflect; Импорт Static cn.zq.util.print.print; Импорт java.io.printstream; Импорт Static cn.zq.util.print.*; открытый класс printTest {статический класс Person {Private Static Int Counter; Приватный окончательный идентификатор int = counter ++; public String toString () {return getClass (). getSiMplename () + id; }} public static void main (string [] args) бросает исключение {print ("-print non array--"); print (new Object ()); print ("-печати одномерной массивы основных типов-"); int [] is = new int [] {1, 22, 31, 44, 21, 33, 65}; print (is); print ("-печатать двухмерный массив основных типов-"); int [] [] ISS = new int [] [] {{11, 12, 13, 14}, {21, 22,}, {31, 32, 33}}; Печать (ISS); print ("-печатная одномерная массива не-базовых типов-"); Человек [] люди = новый человек [10]; for (int i = 0; i <persons.length; i ++) {persons [i] = new Person (); } print (люди); Печать (люди); print ("-распечатать двумерный массив непримитивых типов-"); Person [] [] persons2 = new Person [] [] {{new Person ()}, {new Person (), new Person ()}, {new Person (), New Person (), New Person (), New Person (),},}; Печать (Persons2); print ("-печати пустого массива-"); print (new int [] {}); print ("-печать массив с нулевыми значениями-"); Object [] object = new Object [] {new Person (), null, new Object (), New Integer (100)}; print (Objects); print ("-печати двумерного массива для особых случаев-"); Object [] [] Objects2 = новый объект [3] []; Objects2 [0] = new Object [] {}; Objects2 [2] = Objects; print (Objects2); print ("-вывести результат одномерного массива в файл-"); Printsstream out = new PrintStream ("out.c"); попробуйте {print (Iss, out); } наконец {out.close (); } print ("-output формата-"); Формат (« %-6d %s %b %s», 10086, «IS», True, ISS); /** * Некоторые часто используемые методы классов инструментов печати перечислены выше, * Есть также некоторые незарегистрированные методы, пожалуйста, проверьте это самостоятельно. */}} Выход:
-Партить без ареста-java.lang.object@61de33-Партитный одномерный массив основных типов-[1, 22, 31, 44, 21, 33, 65]-Двумерный массив основных типов-[11, 12, 13, 14], [21, 22], [31, 32, 33]--Пп. Person1, Person2, Person3, Person4, Person5, Person6, Person7, Person8, Person9]-Двумерный массив типа не-базового типа-[Person10], [Person11, Person12], [Person13, Person14, Person15]]-ПРИНЦИОННАЯ МЕСТО-[]--print Array с нулевыми ценностями-[Person16, Null, Java.lang. -Партитный двухмерный массив в особых случаях-[[], NULL, [Person16, Null, Java.lang.object@ca0b6, 100]]-Партить результат одномерного массива к файлу-вывод формата-10086-это правда [[11, 12, 13, 14], [21, 22], [31, 32, 33]]]
Выходной файл:
Видно, что класс инструментов печати уже имеет возможность печатать основные типы одномерных массивов и многомерных массивов. Вообще говоря, приведенный выше класс инструментов довольно практичен, чтобы не писать код вручную каждый раз, когда вы хотите видеть содержимое в массиве. Это было бы слишком хлопотно. Просто используйте класс инструментов печати в будущем. Как удобно.
Класс инструментов выше работает очень хорошо, но если есть требование: дайте вам массив (и, возможно, другие контейнеры), вы можете создать для меня список. Так что мы должны делать? На самом деле, Arrays.aslist не всегда получают результаты, которые мы ожидаем. Хотя Java5 добавляет дженерики, он имеет ограничения и не может быть таким общим, как шаблоны C ++. Это именно потому, что в Java есть основные типы. Даже если есть автоматический механизм обертывания, его нельзя использовать с дженериками. Тип параметра должен быть определенного типа, а не основного типа. Вот решение для вашего собственного:
Пакет cn.zq.util; импортировать java.lang.reflect.array; импортировать java.util.arraylist; импортировать java.util.arrays; Импорт java.util.enumeration; импортировать java.util.iterator; импортировать java.util.list; импортировать java.util.map; public class collectionutils {public static <?> aSlist (Object obj) {return convertToList (makeiterator (obj)); } public static <t> list <T> ConvertToList (итератор <t> итератор) {if (iterator == null) {return null; } List <t> list = new ArrayList <t> (); while (iterator.hasnext ()) {list.add (iterator.next ()); } return List; } @Suppresswarnings ({"rawtypes", "unchecked"}) public static iterator <?> Makeiterator (Object obj) {if (obj exantyof iterator) {return (iterator <?>) Obj; } if (obj == null) {return null; } if (obj ancessionof map) {obj = ((map <?,?>) obj) .EntrySet (); } Итератор <?> Iterator = null; if (obj экземпляр итерабильный) {iterator = ((iterable <?>) obj) .iterator (); } else if (obj.getClass (). isarray ()) {// object [] objs = (object []) obj; // или массивы примитивных типов не могут быть преобразованы, как этот список ArrayList = новый 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 ancessionof enumeration) {iterator = new enumerationiterator ((перечисление) obj); } else {iterator = arrays.aslist (obj) .iterator (); } вернуть итератор; } public Static Class Enumerationiterator <t> реализует итератор <t> {private enumeration <t> enumeration; public enumerationiterator (перечисление <t> enumeration) {this.enumeration = enumeration; } public boolean hasNext () {return enumeration.hasmoreElements (); } public t next () {return enumeration.nextelement (); } public void remove () {бросить новый UnsupPortedOperationException (); }}}Тестовый код:
Пакет cn.zq.array.reflect; импортировать java.util.iterator; импортировать java.util.list; Импорт cn.zq.array.reflect.printtest.person; импортировать cn.zq.util.collectionutils; открытый класс CollectionUtilStest {public static void main (string [] args) {System.out.println ("--- Один размерный массив базового типа-"); int [] nums = {1, 3, 5, 7, 9}; List <?> List = collectiontils.aslist (nums); System.out.println (список); System.out.println ("-не базовый тип одномерный массив-"); Person [] persons = new Person [] {new Person (), New Person (), New Person (),}; Список <Derson> PersonList = (List <Person>) CollectionTils.aslist (Persons); System.out.println (PersonList); System.out.println (PersonList); System.out.println ("-итератор-"); Iterator <person> iterator = personlist.iterator (); List <derss> personList2 = (list <derss>) collectiontils.aslist (итератор); System.out.println (PersonList2); }}Выход:
-Одномерный массив с основным типом-[1, 3, 5, 7, 9]-Одномерный массив-не-базовый тип-[Person0, Person1, Person2]-[Person0, Person1, Person2]
В библиотеке классов Java Container это можно разделить на сборку, карту и массив. Поскольку итератор (и раннее перечисление интерфейса наследия) является общим интерфейсом всех контейнеров, а интерфейс сбора от итерационного (итератор этого интерфейса вернет итератор), эти ситуации обрабатываются один за другим в методе Makeiterator. Для типов карт необходимо вызвать только метод intrintSet (). Для классов, которые реализуют итерабильный интерфейс (включая коллекцию), вызовите iterator (), чтобы напрямую получить объект итератора. Для типов перечисления используйте адаптер Enumerationiterator для адаптации. Для массивов используйте рефлексию массива, чтобы пройти массив в ArrayList, и вызовите метод Arrays.aslist (), чтобы создать список для других типов. CollectionUtils также предоставляет некоторые другие методы для преобразования, и вы можете добавить необходимые методы по мере необходимости.
Резюме: Отражение массива предоставляет более удобные и гибкие методы для конструкций, где могут появиться массивы, чтобы не писать более неприятные высказывания. Эта гибкость оплачивает цену производительности, и на самом деле не нужно использовать отражение массива, когда отражение массива вообще не требуется. Использовать рефлексии массива отличается по фактическому развитию. Выберите, использовать ли массивы отражения в соответствии с потребностями. Лучший способ - исследовать путь через практику, писать так, как вы думаете, и постоянно улучшаться на практике.