java - java reflection depth understanding of Java reflection

Depth understanding of Java reflection

 

  To understand the principle of reflection, we must first understand what type of information. Let's Java runtime information identifying objects and classes, there are two ways: one is the traditional RTTI, which assumes we already know at compile-time type information for all; the other is a reflection mechanism that allows us find and use information on classes at runtime.

1, Class Objects

  Understand how RTTI in Java, you first need to know the type of information at run time is how to represent, this is done by the Class object, which contains information about the class. Class object is used to create all the "normal" objects, Java objects to perform RTTI using the Class, even if you are performing a similar type conversion such operations.

  Each class will have a corresponding Class object, is stored in the .class file. All classes are at the first time you use it, dynamically loaded into the JVM, when the program creates a static member of a class of reference, it will load the class. Class objects are only loaded when needed, static initialization is done when the class is loaded.

Copy the code
public class TestMain {
    public static void main(String[] args) {
        System.out.println(XYZ.name);
    }
}

class XYZ {
    public static String name = "luoxn28";

    static {
        System.out.println("xyz静态块");
    }

    public XYZ() {
        System.out.println("xyz构造了");
    }
}
Copy the code

The output is:

  Class loader first checks whether the Class object of this class has been loaded before, if not already loaded, the default class loader will look for the corresponding .class file based on the class name.

  Want to use run-time type information, you must obtain an object (such as a class Base objects) Class object reference, use the function Class.forName ( "Base") can achieve this purpose, or use base.class. Note that there is very interesting, use the function ".class" to create a Class object when the reference is not automatically initialize the Class object, using forName () will automatically initialize the Class object. In order to use the class to do the preparatory work generally have the following three steps:

  • Load: By class loader, bytecode corresponding to find, create a Class object
  • Links: class byte code verification, the space allocated for the static field
  • Initialization: If the class has a superclass, then its initialization, performs static initialization and static initialization block
Copy the code
Base class {public 
    static int NUM =. 1; 
    
    static { 
        System.out.println ( "Base" + NUM); 
    } 
} 
public class the Main { 
    public static void main (String [] args) { 
        // does not initialize static blocks 
        Class = Base.class of clazz1; 
        System.out.println ( "------"); 
        // initializes 
        Class = clazz2 the Class.forName ( "zzz.Base"); 
    } 
}
Copy the code

2, do first cast before checking

  The compiler will check the legality of the type of downcast, if not legal to throw an exception. Before down conversion type, instanceof Analyzing be used.

Copy the code
class Base { }
class Derived extends Base { }

public class Main {
    public static void main(String[] args) {
        Base base = new Derived();
        if (base instanceof Derived) {
            // 这里可以向下转换了
            System.out.println("ok");
        }
        else {
            System.out.println("not ok");
        }
    }
}
Copy the code

3, the reflection: the runtime class information

  If you do not know the exact type of an object, RTTI can tell you, but there is a premise: this type must be known at compile time, in order to use RTTI to identify it. Class class libraries together with java.lang.reflect reflections of support, the library comprises a Field, Method and Constructor classes, these classes of objects created by the JVM startup to indicate members corresponding to the unknown class. In this case you can use Contructor create new objects, retrieve and modify the class field associated with the Field object get () and set () method, using invoke () method calls the method associated with a Method object. In addition, can also call getFields (), getMethods () and getConstructors () and many convenient method to returns an array of fields, methods, and constructors object, so the object information may be fully defined at run time, and at compile time you do not need to know anything about the class.

  Reflection and there is no magic, when dealing with reflected by the object of an unknown type, JVM simply checking the object, to see which particular class it belongs to. Therefore, the class .classfor the JVM must be accessible, either, or obtained from the network on the local machine. So for the difference between the real and the reflective RTTI only comprising:

  • RTTI, the compiler opens and checks .class file at compile time
  • Reflective, open and runtime checking .class file
Copy the code
public class Person implements Serializable {

    private String name;
    private int age;
// get/set方法
}
public static void main(String[] args) {
    Person person = new Person("luoxn28", 23);
    Class clazz = person.getClass();

    Field[] fields = clazz.getDeclaredFields();
    for (Field field : fields) {
        String key = field.getName();
        PropertyDescriptor descriptor = new PropertyDescriptor(key, clazz);
        Method method = descriptor.getReadMethod();
        Object value = method.invoke(person);

        System.out.println(key + ":" + value);

    }
}
Copy the code

  By the above getReadMethod () get class method calls the function can be invoked by the class method set getWriteMethod () method. Generally speaking, we do not need to use the reflection tools, but they are creating dynamic code will be more useful reflection to support other features in Java, such as serialized JavaBean objects and so on.

4, dynamic proxies

  Proxy mode in order to provide additional or different operations, and used to replace the inserted object "real" objects, these operations involve communication "real" object and thus act as an intermediary agent typically role. Java's dynamic proxy agent more than a step forward ideas, it can dynamically create and proxy and dynamically handle calls to the proxy approach. In the dynamic proxy all calls made will be redirected to a single call processor on which the work is to reveal the type of call and determine the appropriate strategy. The following is an example of a dynamic proxy:

Interface and implementation class:

Copy the code
public interface Interface {
    void doSomething();
    void somethingElse(String arg);
}
public class RealObject implements Interface {
    public void doSomething() {
        System.out.println("doSomething.");
    }
    public void somethingElse(String arg) {
        System.out.println("somethingElse " + arg);
    }
}
Copy the code

Dynamic proxy object handler:

Copy the code
public class DynamicProxyHandler implements InvocationHandler {
    private Object proxyed;
    
    public DynamicProxyHandler(Object proxyed) {
        this.proxyed = proxyed;
    }
    
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
        System.out.println("代理工作了.");
        return method.invoke(proxyed, args);
    }
}
Copy the code

Test categories:

Copy the code
public class Main {
    public static void main(String[] args) {
        RealObject real = new RealObject();
        Interface proxy = (Interface) Proxy.newProxyInstance(
                Interface.class.getClassLoader(), new Class[] {Interface.class},
                new DynamicProxyHandler(real));
        
        proxy.doSomething();
        proxy.somethingElse("luoxn28");
    }
}
Copy the code

Output:

  Proxy can be created by calling the static method Proxy.newProxyInstance () dynamic proxy, this method needs to be a class loader, a list of interfaces implemented in the agent (not a class or an abstract class), and InvocationHandler of a class you want to achieve. Dynamic proxy can redirect all calls to the call processor, it is often invokes the constructor processors pass a reference to the "real" objects, which will be called upon to perform intermediary processor tasks, it forwards the request.

  To understand the principle of reflection, we must first understand what type of information. Let's Java runtime information identifying objects and classes, there are two ways: one is the traditional RTTI, which assumes we already know at compile-time type information for all; the other is a reflection mechanism that allows us find and use information on classes at runtime.

1, Class Objects

  Understand how RTTI in Java, you first need to know the type of information at run time is how to represent, this is done by the Class object, which contains information about the class. Class object is used to create all the "normal" objects, Java objects to perform RTTI using the Class, even if you are performing a similar type conversion such operations.

  Each class will have a corresponding Class object, is stored in the .class file. All classes are at the first time you use it, dynamically loaded into the JVM, when the program creates a static member of a class of reference, it will load the class. Class objects are only loaded when needed, static initialization is done when the class is loaded.

Copy the code
public class TestMain {
    public static void main(String[] args) {
        System.out.println(XYZ.name);
    }
}

class XYZ {
    public static String name = "luoxn28";

    static {
        System.out.println("xyz静态块");
    }

    public XYZ() {
        System.out.println("xyz构造了");
    }
}
Copy the code

The output is:

  Class loader first checks whether the Class object of this class has been loaded before, if not already loaded, the default class loader will look for the corresponding .class file based on the class name.

  Want to use run-time type information, you must obtain an object (such as a class Base objects) Class object reference, use the function Class.forName ( "Base") can achieve this purpose, or use base.class. Note that there is very interesting, use the function ".class" to create a Class object when the reference is not automatically initialize the Class object, using forName () will automatically initialize the Class object. In order to use the class to do the preparatory work generally have the following three steps:

  • Load: By class loader, bytecode corresponding to find, create a Class object
  • Links: class byte code verification, the space allocated for the static field
  • Initialization: If the class has a superclass, then its initialization, performs static initialization and static initialization block
Copy the code
Base class {public 
    static int NUM =. 1; 
    
    static { 
        System.out.println ( "Base" + NUM); 
    } 
} 
public class the Main { 
    public static void main (String [] args) { 
        // does not initialize static blocks 
        Class = Base.class of clazz1; 
        System.out.println ( "------"); 
        // initializes 
        Class = clazz2 the Class.forName ( "zzz.Base"); 
    } 
}
Copy the code

2, do first cast before checking

  The compiler will check the legality of the type of downcast, if not legal to throw an exception. Before down conversion type, instanceof Analyzing be used.

Copy the code
class Base { }
class Derived extends Base { }

public class Main {
    public static void main(String[] args) {
        Base base = new Derived();
        if (base instanceof Derived) {
            // 这里可以向下转换了
            System.out.println("ok");
        }
        else {
            System.out.println("not ok");
        }
    }
}
Copy the code

3, the reflection: the runtime class information

  If you do not know the exact type of an object, RTTI can tell you, but there is a premise: this type must be known at compile time, in order to use RTTI to identify it. Class class libraries together with java.lang.reflect reflections of support, the library comprises a Field, Method and Constructor classes, these classes of objects created by the JVM startup to indicate members corresponding to the unknown class. In this case you can use Contructor create new objects, retrieve and modify the class field associated with the Field object get () and set () method, using invoke () method calls the method associated with a Method object. In addition, can also call getFields (), getMethods () and getConstructors () and many convenient method to returns an array of fields, methods, and constructors object, so the object information may be fully defined at run time, and at compile time you do not need to know anything about the class.

  Reflection and there is no magic, when dealing with reflected by the object of an unknown type, JVM simply checking the object, to see which particular class it belongs to. Therefore, the class .classfor the JVM must be accessible, either, or obtained from the network on the local machine. So for the difference between the real and the reflective RTTI only comprising:

  • RTTI, the compiler opens and checks .class file at compile time
  • Reflective, open and runtime checking .class file
Copy the code
public class Person implements Serializable {

    private String name;
    private int age;
// get/set方法
}
public static void main(String[] args) {
    Person person = new Person("luoxn28", 23);
    Class clazz = person.getClass();

    Field[] fields = clazz.getDeclaredFields();
    for (Field field : fields) {
        String key = field.getName();
        PropertyDescriptor descriptor = new PropertyDescriptor(key, clazz);
        Method method = descriptor.getReadMethod();
        Object value = method.invoke(person);

        System.out.println(key + ":" + value);

    }
}
Copy the code

  By the above getReadMethod () get class method calls the function can be invoked by the class method set getWriteMethod () method. Generally speaking, we do not need to use the reflection tools, but they are creating dynamic code will be more useful reflection to support other features in Java, such as serialized JavaBean objects and so on.

4, dynamic proxies

  Proxy mode in order to provide additional or different operations, and used to replace the inserted object "real" objects, these operations involve communication "real" object and thus act as an intermediary agent typically role. Java's dynamic proxy agent more than a step forward ideas, it can dynamically create and proxy and dynamically handle calls to the proxy approach. In the dynamic proxy all calls made will be redirected to a single call processor on which the work is to reveal the type of call and determine the appropriate strategy. The following is an example of a dynamic proxy:

Interface and implementation class:

Copy the code
public interface Interface {
    void doSomething();
    void somethingElse(String arg);
}
public class RealObject implements Interface {
    public void doSomething() {
        System.out.println("doSomething.");
    }
    public void somethingElse(String arg) {
        System.out.println("somethingElse " + arg);
    }
}
Copy the code

Dynamic proxy object handler:

Copy the code
public class DynamicProxyHandler implements InvocationHandler {
    private Object proxyed;
    
    public DynamicProxyHandler(Object proxyed) {
        this.proxyed = proxyed;
    }
    
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
        System.out.println("代理工作了.");
        return method.invoke(proxyed, args);
    }
}
Copy the code

测试类:

Copy the code
public class Main {
    public static void main(String[] args) {
        RealObject real = new RealObject();
        Interface proxy = (Interface) Proxy.newProxyInstance(
                Interface.class.getClassLoader(), new Class[] {Interface.class},
                new DynamicProxyHandler(real));
        
        proxy.doSomething();
        proxy.somethingElse("luoxn28");
    }
}
Copy the code

Output:

  Proxy can be created by calling the static method Proxy.newProxyInstance () dynamic proxy, this method needs to be a class loader, a list of interfaces implemented in the agent (not a class or an abstract class), and InvocationHandler of a class you want to achieve. Dynamic proxy can redirect all calls to the call processor, it is often invokes the constructor processors pass a reference to the "real" objects, which will be called upon to perform intermediary processor tasks, it forwards the request.

Guess you like

Origin www.cnblogs.com/LCharles/p/11311332.html