preface

Using introspection is safer and more reliable than using reflection directly. Java’s reflection mechanism is special, and it is different from ordinary programming methods, which can easily break the encapsulation of a class. If you don’t practice well, it’s easy to go astray. It doesn’t matter, many times we can also use Java’s introspection mechanism.

This article will show you what Java’s introspection mechanism is and how to use it.

Please give a third to the second husband first, and then read on, thank you.


What is Java’s introspection mechanism?

Introspection is one of the basic research methods in psychology. Introspection method is also called self-observation method. It’s a subjective phenomenon that happens internally, that we ourselves are aware of. It is also an observation of one’s own subjective experience and its changes. Because of its subjectivity, introspection has been a long-term debate in psychology since ancient times. Whether it’s objective, whether it’s reliable. In addition, introspection can also be regarded as self-reflection, which is also the self-thinking emphasized by Confucianism. In this sense it can be applied to the computer world, such as the Java introspection mechanism and the Cocoa introspection mechanism.

Introspector in Java language is a default processing method of Bean class attributes and events. For example, if class A has an attribute name, we can use getName,setName to get its value or set A new value. The default rule is to access the name attribute by getName/setName. Java provides a set of apis to access getter/setter methods for a property that you don’t need to know (but you’d better). These apis are stored in the package Java.Beans.

The general approach is to obtain the BeanInfo information of an object through the class Introspector, and then obtain the PropertyDescriptor through the BeanInfo, which can get the getter/setter method corresponding to a property. We can then invoke these methods through the reflection mechanism.

That’s what the encyclopedia says. Java introspection is ultimately implemented with Java reflection. So why not just use reflection instead of introspection?


Using introspection instead of direct reflection prevents the encapsulation of a class from being broken

We define a person’s type, which includes two attributes: age and adult status. When you change the age attribute, you also change the age attribute. We assume that 18 and older are adults, otherwise they are minors.

import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.text.MessageFormat;

class Person {
    /** * Age of 18 */
    private static final int ADULT_AGE = 18;

    /** * Age */
    private int     age;
    /** * Is an adult */
    private boolean adult;

    public int getAge(a) {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
        this.adult = age >= ADULT_AGE;
    }

    public boolean isAdult(a) {
        return adult;
    }

    public String toString(a) {
        return MessageFormat.format("Age: {0}, adult: {1}", age, adult); }}/ * * *@authorThe white hat of the two masters https://le-yi.blog.csdn.net/ */
public class Test {
    /** * Use reflection to modify object properties *@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);
    }

    /** * Use introspection to modify object properties *@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("The reflection modification property breaks the encapsulation of the class, causing its internal state to be incorrect:");
        System.out.println(p);

        changeObjectFieldByIntrospector(p, "age".18);
        System.out.println("Introspection modifying properties does not break class encapsulation:"); System.out.println(p); }}Copy the code

As you can see, reflection breaks the logic encapsulated in the class by modifying the property directly (20 years old but not adult).

Introspection, on the other hand, does not break the encapsulation of the class because the set method is still called to modify the property, that is, the same method is called to modify the object property normally.

Of course because the introspective nature actually is also a reflection, can be said to be the encapsulates the reflex, so if you right on the reflection, is safe, we can according to the property name to obtain corresponding set and get methods, and then to call, but this kind of circumstance introspection is more convenient to use and, after all, there is no need to reinvent a car wheels, The round wheel has been the brainchild of many, many years.

So the question is, since introspection is just calling the set and get methods, why don’t I call the set and get methods directly instead of using introspection?


Use introspection to write generic tools as well

Since introspection can capture information dynamically, just like reflection, common tools or frameworks can be implemented. Here we implement a utility method that can copy the property values of two objects of any type.

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 {
    /** * Age of 18 */
    private static final int ADULT_AGE = 18;

    /** * Name */
    private final String  name;
    /** * height */
    private       int     height;
    /** * Age */
    private       int     age;
    /** * Is an adult */
    private       boolean adult;

    public Person(String name) {
        this.name = name;
    }

    public String getName(a) {
        return name;
    }

    public int getHeight(a) {
        return height;
    }

    public void setHeight(int height) {
        this.height = height;
    }

    public int getAge(a) {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
        this.adult = age >= ADULT_AGE;
    }

    public boolean isAdult(a) {
        return adult;
    }

    public String toString(a) {
        return MessageFormat.format("Name: {0}, height: {1}, age: {2}, adult: {3}", name, height, age, adult); }}/ * * *@authorThe white hat of the two masters https://le-yi.blog.csdn.net/ */
public class Test {
    /** * copy the readable value of orig to the writable value of 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("Two-headed.");
        p2.setAge(18);
        p2.setHeight(180);
        System.out.println(p2);

        Person p1 = new Person("The big one.");
        System.out.println(p1);

        System.out.println("Copy the value of the second master's readable property to the larger master's writable property:"); copyProperties(p1, p2); System.out.println(p1); }}Copy the code

As you can see, the name is not copied, and all the other property values are copied. That’s what we want.

Introspection is a good guarantee of class encapsulation, and at the same time has the ability to dynamically obtain object properties, and dynamically modify object properties.

The other is my two husband let the big husband grow tall, grow up, adult. I snuck in on that, Kesson.


The end of the

As with reflection, ordinary programs probably don’t need to write introspection code. But with a handy tool like Apache’s Beanutils, I can’t really figure out how to implement it without reflection and introspection. Even if we never need introspection, understanding the mechanics is of great benefit to us.