Если кто-то снова спросит вас об отражении в Java, киньте ему эту статью

Java

В Java не вся информация о типах может быть ясной на этапе компиляции, а некоторая информация о типах должна быть определена во время выполнения.Этот механизм называется RTTI, который по-английски называется RTTI.Run-Time Type Identification, то есть рантайм-распознавание типов, есть ли вкус "единства знания и действия"? Распознавание типов во время выполнения в основном реализуется классом Class.

В нашей ежедневной учебе и работе есть некоторые знания, которые мы можем приобрести, читая книги; но есть и такие знания, которые нам не нужны, и нам нужно практиковать их, чтобы получить истинное знание — это может быть «единство знания и действия». ", за которую выступает Ван Янмин.

01. Класс

В Java мы часто используем ключевое слово «класс» (первая буква — строчная с) для определения класса, говоря, что этот класс является абстракцией определенного класса объектов. Например, если Ван Эр — известный автор в Интернете, мы можем просто определить класс автора следующим образом:

package com.cmower.java_demo.fifteen;

class Author {
	private String pen_name;
	private String real_name;
}

Теперь мы хотим узнать некоторую информацию о самом классе Writer (например, имя класса), что нам делать? В это время вам нужно использовать класс «Класс» (первая буква — заглавная C), который содержит информацию, относящуюся к классу. См. следующий код:

public class Test {
	public static void main (String [] args) {
		Author wanger = new Author();
		Class c1 = wanger.getClass();
		System.out.println(c1.getName());
		//输出 com.cmower.java_demo.fifteen.Author
	}
}

Когда мы создаем объект автора Wanger, мы можем передатьwanger.getClass()Получите объект класса Вангера, черезc1.getName()Можно получить имя класса объекта Вангера.

Представьте себе, после пяти лет целенаправленной практики Ван Эр превратился из писателя-энтузиаста в писателя. Давайте представим это с кодом:

package com.cmower.java_demo.fifteen;

class Author {
	private String pen_name;
	private String real_name;
}

class Writer extends Author {
	private String honour;
}

public class Test {
	public static void main (String [] args) {
		Author wanger = new Writer();
		Class c1 = wanger.getClass();
		System.out.println(c1.getName());
		//输出 com.cmower.java_demo.fifteen.Writer
	}
}

В приведенном выше примере, даже если мы преобразуем wanger ссылки на объект Writer в Author, тип объекта класса для wanger по-прежнему будет Writer (что можно определить по выходному результату). То есть,Java может автоматически идентифицировать информацию о типе во время выполнения, он не потеряет информацию о реальном типе (Writer) wanger, поскольку ссылочным типом wanger является Author. Как Java это делает?

Когда Java создает объект определенного класса, например объект класса Writer, Java проверяет, есть ли в памяти соответствующий объект Class. Если в памяти нет соответствующего объекта Class, то Java будет искать определение класса Writer в файле .class и загружать объект Class класса Writer.

После загрузки объекта класса его можно использовать для создания всех объектов этого типа. Другими словами, каждый объект будет иметь соответствующий объект класса во время выполнения, а объект класса содержит информацию о типе объекта. Следовательно, мы можем узнать «настоящий» тип объекта через объект Class, и он не будет потерян из-за повышения приведения.

02. Другие способы получения предметов класса

В использованииgetClass()Когда метод получает объект Class класса, мы должны сначала получить объект этого класса, такой как Wanger, упомянутый выше. Если мы не получили объект этого класса раньше, нам нужно получить объект Class класса двумя другими способами:

Class c2 = Writer.class;
System.out.println(c2.getName());

try {
	Class c3 = Class.forName("com.cmower.java_demo.fifteen.Writer");
	System.out.println(c3.getName());
} catch (ClassNotFoundException e) {
	e.printStackTrace();
}

1) При использовании.classЧтобы получить объект класса, объект класса не инициализируется автоматически, а инициализация откладывается до тех пор, пока не будет выполнена первая ссылка на статический метод или нефинальное статическое поле. Это не только проще, но и безопаснее, поскольку проверяется во время компиляции (и, следовательно, его не нужно помещать в блок try).

2)Class.forNameОбъект Class инициализируется автоматически, но необходимо указать имя класса и поместить его в блок try.

03. Общие методы, предоставляемые классом Class

Класс Class предоставляет нам несколько очень полезных методов, таких какgetName()используется для возврата имени класса,getPackage()Возвращает имя пакета, в котором находится класс.

Мы также можем воспользоваться классом, предоставляемымnewInstance()метод для создания объекта соответствующего класса, например:

Class c2 = Writer.class;
System.out.println(c2.getName());

try {
	Writer wangsan = (Writer) c2.newInstance();
	System.out.println(wangsan);
	// 输出:com.cmower.java_demo.fifteen.Writer@7852e922
} catch (InstantiationException | IllegalAccessException e1) {
	e1.printStackTrace();
}

Поскольку мы не использовали дженерики при создании объекта класса c2, поэтомуnewInstance()Возвращенный тип объекта должен быть приведен к Writer. Мы можем сделать улучшения на этой основе, примеры следующие:

Class<Writer> c4 = Writer.class;
System.out.println(c4.getName());

try {
	Writer wangsan = c4.newInstance();
	System.out.println(wangsan);
	// 输出:com.cmower.java_demo.fifteen.Writer@7852e922
} catch (InstantiationException | IllegalAccessException e1) {
	e1.printStackTrace();
}

04. Отражение

Мы также можем пройтиgetFields()Получите все общедоступные измененные поля черезgetMethods()Возвращает все общедоступные измененные методы.

Мы можем даже пройтиgetDeclaredFields()Получите больше полей, включая общедоступные, защищенные, доступ по умолчанию (пакет) и частные поля, но не унаследованные поля. соответствующий,getDeclaredMethods()чтобы получить больше методов. Пример выглядит следующим образом:

package com.cmower.java_demo.fifteen;

import java.lang.reflect.Field;
import java.lang.reflect.Method;

class Author {
	private String pen_name;
	private String real_name;
}

class Writer extends Author {
	private String honour;

	private void makeMoney() {
		System.out.println("很多很多钱");
	}
}

public class Test {
	public static void main(String[] args) {

		Class<Writer> c4 = Writer.class;
		System.out.println(c4.getName());

		try {
			Writer wangsan = c4.newInstance();
			System.out.println(wangsan);

			Field[] fields = c4.getDeclaredFields();
			for (Field field : fields) {
				System.out.println(field.getName());
			}

			Method[] methods = c4.getDeclaredMethods();
			for (Method method : methods) {
				System.out.println(method.getName());
			}
		} catch (InstantiationException | IllegalAccessException e1) {
			e1.printStackTrace();
		}

	}
}

Приведенный выше пример на самом деле включает отражение.Поле, метод (и конструктор, не упомянутый в примере) взяты из библиотеки классов java.lang.reflect. Класс Class вместе с библиотекой классов java.lang.reflect поддерживает концепцию отражения.

Иногда нам нужно прочитать строку байт-кодов из файла на диске или из сетевого файла и преобразовать ее в класс, в этом случае нам нужно использовать отражение. Самый распространенный типичный пример — отражение строки JSON-строк (исходной формой могут быть байтовые массивы при передаче по сети) в объекты соответствующего типа.

FastJSON, предоставляемый Alibaba, обеспечиваетtoJSONString()а такжеparseObject()методы для преобразования объектов Java в JSON и обратно. Вызов метода toJSONString преобразует объект в строку JSON, а метод parseObject, в свою очередь, преобразует строку JSON в объект. Внутреннее использование FastJSON — это механизм отражения.

package com.cmower.common.util;

import java.io.UnsupportedEncodingException;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.alibaba.fastjson.JSON;

@SuppressWarnings("all")
public class JsonUtil {
	private static Log logger = LogFactory.getLog("json");

	public static byte[] objectToByte(Object obj) throws UnsupportedEncodingException {
		String jsonStr = JSON.toJSONString(obj);
		logger.debug("序列化后数据:" + jsonStr);
		return jsonStr.getBytes("UTF-8");
	}

	public static <T> T byteToObject(byte[] data, Class<T> obj) throws UnsupportedEncodingException {
		String objectString = new String(data, "UTF-8");
		logger.debug("反序列化后数据 : " + objectString);
		return JSON.parseObject(objectString, obj);
	}
	
	public static <T> Object stringToObject(String data, Class<T> obj) throws UnsupportedEncodingException {
		logger.debug("反序列化后数据 : " + data);
		return JSON.parseObject(data, obj);
	}
}

05. Резюме

Чтобы завершить эту статью, я намеренно иГруппа обмена Silence Wang ErОдин из наших технологов болтал с ним и задавал ему несколько глупых вопросов: «Что означает «среда выполнения»? С точки зрения виртуальной машины Java или с точки зрения программиста?»

Он дал мне очень хорошее объяснение и вдохновил меня. Я не мог не чувствовать себя очень стыдно. Как очень старый ученик Java, мои теоретические знания настолько слабы, что я не знаю, есть ли у вас такое замешательство.

Но в этом и прелесть написания, и в процессе объяснения читателям, «как Java распознает информацию о типах во время выполнения», мой разум постепенно прояснился — какой отличный способ улучшить себя!


Предыдущий:Обработка исключений Java: страховка для программы

Следующий:Перечисления Java: маленькое перечисление, элегантное и чистое

Поиск в WeChat »Тихий король 2"Общественный номер, подпишитесь и ответьте"бесплатное видео"Получите 500 ГБ высококачественных обучающих видео (по категориям).