предисловие
Использование интроспекции безопаснее и надежнее, чем непосредственное использование отражения.В Java механизм отражения особенный, он отличается от обычных методов программирования, и легко разрушить инкапсуляцию класса, если вы не будете осторожны. Если вы плохо тренируетесь, легко сойти с ума. Это не имеет значения, много раз мы также можем использовать механизм самоанализа Java.
В этой статье будет рассказано о том, что такое механизм самоанализа в Java и как его использовать.
Пожалуйста, дайте сначала третью роту второму мастеру, а потом читайте дальше, спасибо.
Что такое механизм самоанализа в Java?
Интроспекция является одним из основных методов исследования в психологии. Самонаблюдение также называют самонаблюдением. Это внутреннее, субъективное явление, которое мы сами осознаем. Можно также сказать, что это наблюдение собственного субъективного опыта и его изменений. Из-за своей субъективности интроспекция была предметом давних споров в психологии с древних времен. Спорим, объективна ли она и достоверна. Кроме того, самоанализ также можно рассматривать как саморефлексию, которая также является саморефлексией, подчеркиваемой конфуцианством. С этой точки зрения его можно применить к компьютерной области, такой как механизм самоанализа Java и механизм самоанализа какао.
Интроспектор языка Java — это метод обработки по умолчанию для языка Java свойств и событий класса компонента. Например, в классе A есть атрибут Name, значение которого мы можем получить или установить новое значение через getName, setName. Доступ к свойству Name через getName/setName, это правило по умолчанию. В Java доступен набор API для доступа к методу getter/setter с поддержкой свойств, что позволяет сделать так, чтобы вам не нужно было понимать это правило (но вы все равно должны в нем разобраться), эти API хранятся в пакете Java.beans .
Общая практика заключается в том, чтобы получить информацию BeanInfo об объекте через класс Introspector, а затем получить дескриптор свойства (PropertyDescriptor) через BeanInfo.Через этот дескриптор свойства вы можете получить метод getter/setter, соответствующий свойству, а затем мы will Эти методы могут быть вызваны через механизм отражения.
Выше приведено объяснение энциклопедии. Самоанализ Java в конечном счете реализуется с использованием отражения Java. Так почему бы не использовать рефлексию напрямую, а использовать интроспекцию?
Использование самоанализа вместо прямого использования отражения может предотвратить нарушение инкапсуляции класса.
Мы определяем тип человека, который включает в себя два атрибута: возраст и взрослость. При изменении атрибута возраста одновременно будет изменен атрибут взрослости. Мы предполагаем, что 18 лет и старше — это взрослый, в противном случае — несовершеннолетний.
import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.text.MessageFormat;
class Person {
/**
* 18岁成年
*/
private static final int ADULT_AGE = 18;
/**
* 年龄
*/
private int age;
/**
* 是否成年
*/
private boolean adult;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
this.adult = age >= ADULT_AGE;
}
public boolean isAdult() {
return adult;
}
public String toString() {
return MessageFormat.format("age:{0},adult:{1}", age, adult);
}
}
/**
* @author 二当家的白帽子 https://le-yi.blog.csdn.net/
*/
public class Test {
/**
* 利用反射修改对象属性
* @param o
* @param fieldName
* @param value
* @throws NoSuchFieldException
* @throws IllegalAccessException
*/
public static void changeObjectFieldByReflection(Object o, String fieldName, Object value) throws NoSuchFieldException, IllegalAccessException {
Field field = o.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
field.set(o, value);
}
/**
* 利用内省修改对象属性
* @param o
* @param fieldName
* @param value
* @throws NoSuchFieldException
* @throws IllegalAccessException
*/
public static void changeObjectFieldByIntrospector(Object o, String fieldName, Object value) throws IntrospectionException, InvocationTargetException, IllegalAccessException {
PropertyDescriptor pd = new PropertyDescriptor(fieldName, o.getClass());
pd.getWriteMethod().invoke(o, value);
}
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, IntrospectionException, InvocationTargetException {
Person p = new Person();
changeObjectFieldByReflection(p, "age", 20);
System.out.println("反射修改属性破坏类的封装,使其内部状态错误:");
System.out.println(p);
changeObjectFieldByIntrospector(p, "age", 18);
System.out.println("内省修改属性未破坏类的封装:");
System.out.println(p);
}
}
Как видите, рефлексия разрушает логику, инкапсулированную в классе (20 лет, но не взрослость), потому что напрямую модифицирует свойства.
При интроспекции метод set по-прежнему вызывается для изменения свойств, то есть тот же метод обычно вызывается для изменения свойств объекта, поэтому инкапсуляция класса не будет разрушена.
Конечно, поскольку интроспекция на самом деле является рефлексией по сути, то можно сказать, что она инкапсулирует рефлексию, поэтому при правильном использовании рефлексии она также безопасна.Мы можем получить соответствующий набор и получить методы по имени атрибута, а затем вызвать их , но в данном случае удобнее использовать под самоанализом.Ведь не надо изобретать велосипед.Круглое колесо было кристаллизацией мудрости на протяжении многих лет.
Итак, вопрос в том, что, поскольку интроспекция заключается в вызове методов set и get, почему бы мне не вызывать методы set и get напрямую, а использовать интроспекцию?
Также можно написать общие инструменты, используя самоанализ.
Поскольку интроспекция может динамически получать информацию, как и рефлексия, могут быть реализованы общие инструменты или фреймворки. Здесь мы реализуем служебный метод, который может копировать значения свойств двух объектов любого типа.
import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.text.MessageFormat;
class Person {
/**
* 18岁成年
*/
private static final int ADULT_AGE = 18;
/**
* 名字
*/
private final String name;
/**
* 身高
*/
private int height;
/**
* 年龄
*/
private int age;
/**
* 是否成年
*/
private boolean adult;
public Person(String name) {
this.name = name;
}
public String getName() {
return name;
}
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
this.adult = age >= ADULT_AGE;
}
public boolean isAdult() {
return adult;
}
public String toString() {
return MessageFormat.format("name:{0},height:{1},age:{2},adult:{3}", name, height, age, adult);
}
}
/**
* @author 二当家的白帽子 https://le-yi.blog.csdn.net/
*/
public class Test {
/**
* 将orig的可读属性值拷贝到dest的可写属性中
* @param dest
* @param orig
* @param <T>
* @throws IntrospectionException
* @throws InvocationTargetException
* @throws IllegalAccessException
*/
public static <T> void copyProperties(T dest, T orig) throws IntrospectionException, InvocationTargetException, IllegalAccessException {
BeanInfo beanInfo = Introspector.getBeanInfo(orig.getClass());
PropertyDescriptor[] pds = beanInfo.getPropertyDescriptors();
for (PropertyDescriptor pd : pds) {
Method rm = pd.getReadMethod();
Method wm = pd.getWriteMethod();
if (rm != null
&& wm != null) {
Object value = rm.invoke(orig);
wm.invoke(dest, value);
}
}
}
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, IntrospectionException, InvocationTargetException {
Person p2 = new Person("二当家的");
p2.setAge(18);
p2.setHeight(180);
System.out.println(p2);
Person p1 = new Person("大当家的");
System.out.println(p1);
System.out.println("将二当家的可读属性值拷贝给大当家的可写属性:");
copyProperties(p1, p2);
System.out.println(p1);
}
}
Видно, что имя не скопировано, а другие значения атрибутов скопированы успешно. Это также результат, который мы ожидаем.
Самоанализ гарантирует инкапсуляцию классов и в то же время имеет возможность динамически получать и изменять свойства объекта.
Кроме того, моя вторая голова позволила большеголовой семье подрасти, вырасти и стать взрослой. Я украл это по дешевке, Кайсен.
конец
Как и при отражении, нормальные программы могут не нуждаться в написании интроспективного кода. Но с таким удобным инструментом, как beanutils от apache, без размышлений и без самоанализа я действительно не могу понять, как это сделать. Даже если самоанализ никогда не понадобится, понимание механики принесет нам большую пользу.