1. rtti:
Информация о типе выполнения позволяет вам открывать и использовать информацию типа во время работы программы.
Есть два способа определения информации об объектах и классах при работе в Java: традиционные RTTI и размышления. Давайте поговорим о RTTI.
RTTI: во время выполнения определить тип объекта. Но этот тип должен быть известен во время компиляции.
Давайте возьмем пример, чтобы увидеть использование RTTI. Это включает в себя концепцию полиморфизма: позволяет коду работать только на ссылках на базовый класс, и фактически вызывая методы конкретных подклассов обычно создают конкретный объект (круг, квадрат или треугольник, см. Пример ниже), преобразовать его вверх в форму (игнорируя специфический тип объекта) и используйте анонимный (то есть не зная специфического типа).
Аннотация форма класса {// Это вызывает метод ToString () текущего класса, возвращая фактическое содержание void Draw () {System.out.println (this + "draw ()"); } // объявить toString () как абстрактный тип, интеграция силы для переопределения метода абстрактно открытый строки toString ();} Class Circle Extends Shape {public String toString () {return "circle"; }} класс Square Extends Shape {public String toString () {return "square"; }} класс треугольник расширяет Shape {public String toString () {return "Triangle"; }} public static void main (string [] args) {// При вложении объекта формы в массив списка <shape> он преобразует вверх в форму, теряя тем самым список конкретного типа информации <shape> shapelist = arrays.aslist (new Circle (), new square (), new Triangle ()); // При выходе из массива все элементы этого контейнера удерживаются в виде объектов и автоматически превратят результат в форму. Это основное использование RTTI. для (форма формы: сочинения) {shape.draw (); }}Результатом вывода:
CirgledRaw () SquaredRaw () TriangledRaw ()
При отложении его в массив он будет автоматически трансформироваться до формы, и конкретный тип теряется. При выходе из массива (контейнер списка содержит все как объект), он автоматически преобразует результат обратно в форму. Это основное использование RTTI. Все преобразования типов в Java исправляют во время выполнения, то есть RTTI: во время выполнения, идентифицируйте тип объекта.
Вышеуказанное преобразование не является тщательным. Когда элементы массива вынуждены, объект преобразуется в форму, а не на конкретный тип. Это делается контейнерами и общими системами Java во время компиляции, и существуют операции по преобразованию типов, чтобы обеспечить это во время выполнения.
Конкретный код, который может быть выполнен в подкласс через объект формы, определяется полиморфизмом. Для получения подробной информации это зависит от конкретного объекта, на который указывается ссылка на форму.
Кроме того, используя RTTI, вы можете запросить точный тип объекта, указанный с помощью ссылки на форму, а затем выборочно выполнить метод подкласса.
2. Объект класса:
Чтобы понять, как работает RTTI в Java, вы должны знать, как информация о типе представлена во время выполнения, что выполняется специальным классом объекта.
Объекты класса используются для создания всех «обычных» объектов класса. Java использует объекты класса для выполнения своего RTTI.
Всякий раз, когда собирается новый класс, генерируется объект класса (файл .class). JVM, работающая в этой программе, будет использовать подсистему «Class Loader».
Подсистема загрузчика класса: содержит цепочку загрузчика класса, но только один собственный загрузчик класса, который является частью реализации JVM. Нативные загрузки класса загружают доверенные классы, в том числе классы Java API, обычно с местных дисков. Когда класс должен быть загружен определенным образом для поддержки приложений веб -сервера, можно подключить дополнительные загрузки класса.
2.1. Время загрузки класса:
Этот класс загружается, когда программа создает первую ссылку на статического члена класса. Это доказывает, что конструктор на самом деле является статическим методом класса. При создании нового объекта класса с использованием нового оператора он также будет использоваться в качестве ссылки на статический член класса.
Можно видеть, что программы Java загружаются динамически и загружаются по требованию. Когда класс необходим, загрузчик класса сначала проверит, был ли загружен объект класса этого класса. Если он не был загружен, загрузчик класса по умолчанию найдет файл .class на основе имени класса. Далее находится фаза проверки: при загрузке они принимают проверку, чтобы убедиться, что они не повреждены и не содержат плохого кода Java.
2.2. Связанные с классом методы, NewInstance ()
Ниже приведен пример для демонстрации загрузки объекта класса:
Класс A {// статическая кодовая база, выполняемая, когда она загружается в первый раз, и известно, когда класс загружается путем печати информации static {System.out.println («Загрузка A»); }} класс B {static {System.out.println ("Загрузка b"); }} класс c {static {System.out.println ("Загрузка C"); / новый a (); System.out.println («после нового A»); try {class.forname ("com.itzhai.test.type.b"); } catch (classnotfoundexception e) {System.out.println ("Облако не находить класс B"); } System.out.println ("After class.forname b"); новый c (); System.out.println ("после нового C"); }}Результатом вывода:
Выполнить Main ... Загрузка aafter new Aloading bafter class.forname bloading cafter new c
Видно, что объект класса загружается только при необходимости. Обратите внимание на метод class.forname () здесь:
Метод ForName () - это метод получения ссылки на объект класса. Получив соответствующую ссылку на объект класса, вы можете использовать информацию типа во время выполнения.
Если у вас уже есть интересный объект, вы можете получить ссылку на класс, следуя методу getClass (), предоставленный объектом класса.
Вот код, используемый классом:
Интерфейс x {} интерфейс y {} интерфейс z {} class letter {iltlem () {}; Itled (int i) {};} класс Newletter Extends буквы x, y, z {newletter () {super (1); };} открытый класс classtest { / *** // Получить систему имен класса. // Получить полностью квалифицированную систему имен класса. } public static void main (string [] args) {class c = null; try {// получить ссылку на класс c = class.forname ("com.itzhai.test.type.newletter"); } catch (classnotfoundexception e) {System.out.println ("Не может найти com.itzhai.test.type.newletter"); System.Exit (1); } // Печать Информация о типе интерфейса для (Class Face: c.getInterfaces ()) {printInfo (face); } // Получить справочный класс класса SuperClass up = c.getSuperClass (); Объект obj = null; try {// создать экземпляр класса через метод newInstance () obj = up.newinstance (); } catch (instantiationException e) {System.out.println ("Не может создать экземпляр"); } catch (allogalaccessexception e) {System.out.println ("Не может получить доступ"); } // Печать Информация о типе SuperClass printInfo (obj.getClass ()); }}Вывод:
Имя класса: com.itzhai.test.type.x - это интерфейс? TruesImple Name: Xcanonical Name: com.itzhai.test.type.xclass Название: com.itzhai.test.type.y - это интерфейс? Имя TruesImple: Ycanonical Name: com.itzhai.test.type.yclass Название: com.itzhai.test.type.z - это интерфейс? Имя TruesImple: Zcanonical Name: com.itzhai.test.type.zclass Название: com.itzhai.test.type.letter - это интерфейс? Falsesimple name: Lettercanonical name: com.itzhai.test.type.letter
Обратите внимание, что строка, передаваемая в ForName (), должна использовать полностью квалифицированное имя (включая имя пакета).
С помощью методов, используемых в PrintInfo, вы можете обнаружить полную структуру наследования класса в течение всего времени.
Используя метод класса NewInstance (), это способ реализовать «виртуальный конструктор» для создания экземпляра класса. Ссылка на объект получена, но он указывает на объект буквы при ссылке. Классы, созданные с использованием NewInstance (), должны иметь конструктор по умолчанию. (Через API отражения вы можете использовать любой конструктор для динамического создания объектов класса).
2.3. Литеральные константы класса:
В дополнение к использованию метода getName (), Java также предоставляет другой способ генерировать ссылку на объект класса, то есть с использованием буквальных констант:
Newletter.class;
Этот метод прост и безопасен и проверяется во время компиляции, что делает его более эффективным. Его можно использовать не только для обычных классов, но и для интерфейсов, массивов и основных типов данных. Кроме того, для класса обертки основного типа данных также существует стандартный тип поля. Поле типа - это ссылка на выполнение соответствующего основного объекта класса типа данных. Для объединения рекомендуется использовать форму .class.
2.4. Разница между использованием .class и использованием метода getName () для создания ссылок на объекты:
При создании с .class объект класса не инициализируется автоматически. Шаги создания следующие:
(1) Загрузка выполняется классовым погрузчиком: посмотрите на байт -код (обычно в пути, указанном в группе класса, но не обязательно), а затем создайте объект класса из этих байткодов.
(2) Ссылка проверит байт -код в классе и выделяет пространство для хранения для статического домена. При необходимости все ссылки на другие классы, созданные этим классом, будут анализироваться.
(3) Инициализация Если класс имеет суперкласс, инициализируйте его и выполняет статический инициализатор и блок статической инициализации.
Инициализация откладывается до первой ссылки на статический метод (конструктор неявно статический) или немеренный статический домен:
Class Data1 {статический конечный int a = 1; Статический окончательный двойной b = math.random (); static {System.out.println ("init data1 ..."); }} класс Data2 {static int a = 12; static {System.out.println ("init data2 ..."); }} класс Data3 {static int a = 23; static {System.out.println ("init data3 ..."); }} открытый класс clasStest2 {public static void main (string [] args) {system.out.println ("data1.class:"); Class Data1 = data1.class; System.out.println (data1.a); // data1 System.out.println (data1.b); // data1 инициализированная система.out.println (data2.a); // DATA2 Инициализированный try {class data3 = class.forname ("com.itzhai.test.type.data3"); // data3 инициализировано} catch (classnotfoundexception e) {system.out.println ("Не может найти com.itzhai.test.type.data3 ..."); } System.out.println (data3.a); }}Результатом вывода:
Data1.class: 1Init Data1 ... 0.26771085109184534INIT DATA2 ... 12INIT DATA3 ... 23
Инициализация эффективно достигает как можно более «ленивым».
2.5. Ниже приведены некоторые ситуации для определения того, выполнять ли инициализация:
(1) Синтаксис класса получает ссылку на класс и не вызовет инициализации;
(2) class.forname () генерирует ссылку на класс и немедленно инициализируется;
(3) Если статическое окончательное значение - это «константа компилятора», то это значение можно прочитать без инициализации класса;
(4) Недостаточно обеспечить такое поведение, если просто установить домен для статического финала, например:
Статический окончательный двойной b = math.random ();
(5) Если статический домен является бутифинальным, то при доступе к нему всегда необходимо продвигать и инициализировать;
2.6 Обобщенная классная цитата:
Ссылка на класс представляет точный тип объекта, на который он указывает, а объект является объектом класса класса. В Javase5 объект класса, на который указан ссылкой на класс, может быть квалифицирован генериками, а компилятор может обеспечить соблюдение дополнительных проверок типа:
Class intcls = int.class; // Использовать Generics для определения ссылки, указанной на классе класса <Integer> genintcls = int.class; // Класс без уники может быть переназначена, чтобы указывать на любой другой объект класса intcls = double.class; // Следующее компиляция будет ошибочной // genintcls = double.class;
2.6.1. Используйте подстановочные знаки? Расслабьте ограничения дженериков:
Класс <?> Intcls = int.class; intcls = string.class;
В Javase5 класс <?> Лучше, чем обычный класс, и рекомендуется использовать класс <?>, Даже если они эквивалентны, потому что преимущество класса <?> Заключается в том, что это означает, что вы не происходят или небрежно, но используют неспецифическую ссылку на классы.
Чтобы определить ссылку на класс на определенный тип, или подтип этого типа может использовать подстановочные знаки с расширением, создать область:
Класс <? extends number> num = int.class; // Справочный диапазон num - это число и его подкласс, поэтому вы можете назначить значение num = double.class; num = number.class;
2.6.2. Метод NewInstance () под универсацией:
Using the Class after generics, the object returned by calling newInstance() is of the exact type, but when you use getSuperclass() to get the superclass corresponding to the generic, there are some limitations to the real type: the compiler knows the type of the superclass during the compilation period, but the newInstance() method referenced by this obtained superclass does not return the exact type, but the Object:
Dog Dog = DogCls.newinstance (); Аннотация класса класса Animal {} класс Dog Extens Animal {} // Следующий метод написания неправильный, и он может вернуть только класс <? Super Dog> Type // Class <Animal> AnimalCls = DogCls.getSuperClass (); Класс <? Super Dog> AnimalCls = dogCls.getSuperClass (); // Через полученную ссылку SuperClass вы можете создавать только объекты, которые возвращают объект объекта Object obj = AnimalCls.newinStance (); 2.6.3. Синтаксис нового преобразования: метод CAST ()
Посмотрите прямо на код:
Животное животное = новая собака (); класс <gog> dogcls = dog.class; dog dog = dogcls.cast (животное); // или непосредственно использовать следующий метод трансформации dog = (собака) животное;
Можно найти, что использование метода CAST () проделал дополнительную работу. Этот метод преобразования может использоваться в следующей ситуации: При написании общей полосы, если хранится ссылка на класс, и вы надеетесь выполнить преобразование с помощью этой ссылки на класс, вы можете использовать метод CAST ().
3. Введите экземпляры проверки
3.1. Проверьте перед преобразованием типа
Компилятор позволяет вам свободно выполнять операции назначения преобразования вверх без каких -либо отображаемых операций преобразования, точно так же, как присвоение значений ссылкам на суперкласс.
Однако, если отображаемое преобразование типа не используется, компилятор не позволит вам выполнять задание пониженного. В настоящее время мы могли бы также проверить, является ли объект экземпляром определенного типа, и экземпляр ключевого слова ключевого слова:
if (x экземпляр собаки) ((собака) x) .bark ();
3.2. Форма RTTI:
Итак, до сих пор мы знаем, что формы RTTI включают:
(1) Традиционное преобразование типа (форма)
(2) Объект класса, представляющий тип объекта
(3) Экземпляр ключевого слова
3.3. Динамический экземпляр метода:
Метод класса.
Следующее демонстрирует использование экземпляра и class.isinstance:
Атрибут:
атрибут публичного интерфейса {}Форма:
/** * Создать абстрактный класс */public абстрактного класса Shape {// Это вызывает метод ToString текущего метода ToString Class для получения информации public void draw () {System.out.println (this + ".draw ()"); } // Объявит метод ToString () для абстрагирования, тем самым заставляя наследника переписать метод. абстрактная публичная строка toString ();}Круг:
Общедоступный класс Circle Extens Shape реализует attribute {public String toString () {return "Circle"; }}Квадрат:
Public Class Square расширяет Shape {public String toString () {return "square"; }}Треугольник:
открытый класс треугольник расширяет Shape {public String toString () {return "Треугольник"; }}Проверка типа:
// exancefcircle c = new Circle (); // Определить, является ли экземпляр Superclass System.out.format («Использование exanteOf: %s - это форма? %b/n», C.ToString (), C EncementOf form SuperClass System.out.format («Использование class.isinStance: %s является формой? %b/n», c.toString (), c exanceOf Circle); // определить, является ли экземпляр SuperClass System.out.format («Использование класса. System.out.format («Использование class.isinStance: %s является атрибутом? %B/n», c.toString (), attribute.class.isinstance (c));
Можно обнаружить, что метод экземпляра или класса.
Следующее демонстрирует, как использовать Dynamic Class.Instance:
Сначала создайте класс генератора абстрактного генератора:
Public Abstract Class ShapeCreator {private Random Rand = new Random (10); // возвращать массив типов объектов, предоставленных классом реализации. Вы увидите две формы реализации позже, основываясь на ForName и на основе литеральных константов класса. расширяет форму >> types (); // Случайно генерировать экземпляр объекта типа в массиве типов объектов Public Shape randomshape () {int n = rand.nextint (types (). Size ()); try {return types (). get (n) .newinstance (); } catch (instantiationException e) {e.printstacktrace (); вернуть ноль; } catch (allogalaccessexception e) {e.printstacktrace (); вернуть ноль; }} // Сгенерировать публичную форму случайного массива [] createarray (int size) {shape [] result = new Shape [size]; for (int i = 0; i <size; i ++) {result [i] = randomShape (); } return Result; } // Сгенерировать случайный массив, общий ArrayList Public ArrayList <shail> ArrayList (int size) {ArrayList <Shape> result = new ArrayList <shape> (); Collections.addall (результат, Createarray (размер)); результат возврата; }}Далее напишите реализацию этого абстрактного класса:
/** * Реализация генератора ForName * @author arting * */public class fornamecreator расширяет ShapeCreator {Private Static List <Class <? расширяет Shape >> types = new ArrayList <Class <? расширяет форму >> (); частная статическая строка [] typenames = {"com.itzhai.javanote.entity.circle", "com.itzhai.javanote.entity.square", "com.itzhai.javanote.entity.triangle"}; @Suppresswarnings ("unared") private static void Loader () {for (String name: typenames) {try {types.add ((class <? Extends Shape>) class.forname (name)); } catch (classnotfoundexception e) {e.printstacktrace (); }}} // Инициализировать массив типов, необходимых для загрузки static {loader (); } public List <Class <? Extends Shape >> types () {return Types; }}Наконец, напишите класс, который считает количество форм, используя экземпляр:
открытый класс shapecount {static class shapecounter extends hashmap <string, integer> {public void count (type string) {integer cultity = get (type); if (количество == null) {put (type, 1); } else {put (type, количество + 1); }}} // демонстрировать указание типов объектов через экземпляр ключевого слова Public Static Void Countshapes (Creator ShapeCreator) {ShapeCounter = new ShapeCounter (); для (форма формы: creator.createarray (20)) {if (exantef exanceof indestof uctre) counter.count ("circle"); if (shape exantef square) counter.count ("square"); if (exance of triangle) {counter.count ("Треугольник"); }} System.out.println (счетчик); } public static void main (string [] args) {countshapes (new fornamecreator ()); }}Перепишите реализацию абстрактного класса и переосмыслить его с помощью буквальных констант:
/*** Реализация литерального генератора*/public Class LiteralCreator Extends ShapeCreator {public Static Final List <Class <? Extends Shape >> alltype = collections.unmodifiablelist (arrays.aslist (circle.class, triangle.class, square.class)); Общественный список <класс <? Extends Shape >> types () {return alltype; } public static void main (string [] args) {System.out.println (alltype); }}Теперь используйте Class.Instance, чтобы подсчитать количество форм следующим образом:
/*** Удалите оператор Monotonic EncementOF в исходном ShapeCount, используя Class.InstanceOf Dynamic Test объекта**/Public Class ShapeCount2 {Private Static Final List <Class <? Extends Shape >> Shapetypes = LiteralCreator.alltype; Статический класс ShapeCounter Extends HashMap <String, Integer> {public void Count (String Type) {integer cultity = get (type); if (количество == null) {put (type, 1); } else {put (type, количество + 1); }}} // демонстрировать типы статистических объектов через class.isinstance () public static void countshapes (создатель shapecreator) {shapecounter = new shapecounter (); для (форма формы: creator.createarray (20)) {for (class <? Extends Shape> cls: shapetypes) {if (cls.isinstance (shape)) {counter.count (cls.getSimplename ()); }} System.out.println (счетчик); } public static void main (string [] args) {countshapes (new fornamecreator ()); }}Теперь есть две реализации генератора. Мы можем добавить здесь слой внешнего вида и установить метод реализации по умолчанию:
/*** Теперь есть две реализации генератора. Давайте добавим здесь слой внешнего вида и установим метод реализации по умолчанию */public class formes {public static final creator creator = new LiteralCreator (); публичная статическая форма randomShape () {return creator.randomshape (); } public Static Shape [] createarray (int size) {return creator.createarray (size); } public Static ArrayList <Shore> ArrayList (int size) {return creator.arraylist (size); }} 3.4. Эквивалентность экземпляра и класса:
Результат, сгенерированный экземпляром и isInstance (), точно такой же, сохраняя концепцию типа и определяя, является ли класс или полученный класс этого класса.
equals () такой же, как ==, и, используя этот более практичный объект класса, наследование не учитывается.
System.out.println (new Circle () экземпляр Circle); // truesystem.out.println (shape.class.isinstance (new Circle ())); // truesystem.out.println ((new Circle ()). getClass () == circle.class); // truesystem.out.println ((new Circle (). getClass ()). equals (shape.class)); // ЛОЖЬ