编程知识 cdmana.com

Baozi series -- Java basics Chapter 15_ Java reflection mechanism

Chapter 14 Java The reflex mechanism

image-20201112200950447.png

Overview of reflections

About the understanding of reflection

  • Reflection( Reflection ) Is seen as the key to dynamic language , The reflection mechanism allows programs to use Reflection API Get anything
    Class's internal information , And can directly operate the internal properties and methods of any object .
  • After loading the class , stay Method area of heap memory And there's a Class Object of type ( One Class has only one Class object ), This object contains the complete class structure information . We can see the structure of the class through this object . This object is like a mirror , Look through this mirror to see the structure of the class , therefore , Our image is called : Reflection .

image-20201112184518584.png

frame = Reflection + annotation + Design patterns .

Dynamic language vs Static language

Dynamic language

Is a kind of language that can change its structure at run time : For example, new functions 、 object 、 Even the code can Introduced , Existing functions can be deleted or other structural changes can be made . Generally speaking, code can change its structure according to certain conditions at runtime . The main dynamic language :Object-C、C#、JavaScript、PHP、Python、Erlang.

Static language

Corresponding to dynamic language , A language whose runtime structure is immutable is a static language . Such as Java、C、 C++.

Java It's not dynamic language , but Java It can be called “ Quasi dynamic language ”. namely Java There is a certain dynamic , We can use the reflection mechanism 、 Bytecode operations gain features similar to dynamic languages . Java The dynamic nature of programming makes programming more flexible !

Experience the reflex mechanism “ dynamic ”

// Experience the dynamic nature of reflection 
@Test
public void test2(){

    for(int i = 0;i < 100;i++){
        int num = new Random().nextInt(3);//0,1,2
        String classPath = "";
        switch(num){
            case 0:
                classPath = "java.util.Date";
                break;
            case 1:
                classPath = "java.lang.Object";
                break;
            case 2:
                classPath = "com.atguigu.java.Person";
                break;
        }

        try {
            Object obj = getInstance(classPath);
            System.out.println(obj);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
/*
 Create an object of the specified class .
classPath: Specifies the full class name of the class 
 */
public Object getInstance(String classPath) throws Exception {
   Class clazz =  Class.forName(classPath);
   return clazz.newInstance();
}

What the reflection mechanism can provide

image-20201112184902405.png

relevant API

java.lang.Class: Represents a class 
java.lang.reflect.Method: Method representing class 
java.lang.reflect.Field: Member variables representing the class 
java.lang.reflect.Constructor: The constructor representing the class 

Class Class understanding and acquisition Class Example

Class class

stay Object Class defines the following methods , This method will be inherited by all subclasses :

public final Class getClass()

adopt getClass() Return to one Class object

The return value type of the above method is a Class class , This is Java The source of reflection , In fact, the so-called reflection is well understood from the running results of the program , namely : You can get the name of the class through object reflection .

Information that an object can get from looking in the mirror : Properties of a class 、 Methods and constructors 、 Which classes are implemented mouth . For each class ,JRE Keep an immutable Class Object of type . One Class Object contains A particular structure (class/interface/enum/annotation/primitive type/void/[]) about .

  • Class It's also a class
  • Class Objects can only be created by the system
  • A loaded class is in JVM There will only be one Class example
  • One Class Object corresponds to a load into JVM One of them .class file
  • Every instance of a class remembers who it is by Class Instance generated
  • adopt Class You can get all the loaded structures in a class completely
  • Class Class is Reflection The root of , For anything you want to load dynamically 、 Operation of class , You have to get the corresponding first Class object

Class Class

Class loading process

The procedure goes through javac.exe After the order , One or more bytecode files will be generated (.class ending ).
Then we use java.exe Command to interpret and run a bytecode file . Equivalent to a bytecode file
Load into memory . This process is called class loading . Classes loaded into memory , We call it the runtime class , This runtime class , Just as Class An example of .

let me put it another way ,Class An instance of is corresponding to a runtime class .

Runtime classes loaded into memory , Will cache a certain amount of time . Within this time , We can get this runtime class in different ways .

obtain Class Examples of several ways :( The first three ways need to be mastered )

// Mode one : Call the properties of the runtime class :.class
Class clazz1 = Person.class;
System.out.println(clazz1);
// Mode two : Through the object of the runtime class , call getClass()
Person p1 = new Person();
Class clazz2 = p1.getClass();
System.out.println(clazz2);

// Mode three : call Class Static method of :forName(String classPath)
Class clazz3 = Class.forName("com.atguigu.java.Person");
//        clazz3 = Class.forName("java.lang.String");
System.out.println(clazz3);

System.out.println(clazz1 == clazz2);
System.out.println(clazz1 == clazz3);

// Mode 4 : Using loaders for classes :ClassLoader  ( understand )
ClassLoader classLoader = ReflectionTest.class.getClassLoader();
Class clazz4 = classLoader.loadClass("com.atguigu.java.Person");
System.out.println(clazz4);

System.out.println(clazz1 == clazz4);

// All are true

summary : How to create objects of a class

Mode one :new + Constructors
Mode two : To create a Xxx Class object , You can consider :Xxx、Xxxs、XxxFactory、XxxBuilder Class to see if there is
The existence of static methods . You can call its static method , establish Xxx object .
Mode three : By reflection

Class Examples can be descriptions of what structures

image-20201112193521398.png

understand ClassLoader

Class loading process ---- understand

image-20201112193605124.png

The role of class loaders

image-20201112193627650.png

Class loader classification

image-20201112193658427.png

Java Class compilation 、 The execution process of running

image-20201112193737653.png

Use Classloader load src The configuration file under the directory

@Test
public void test2() throws Exception {

    Properties pros =  new Properties();
    // At this time, the file defaults to the current module Next .
    // The first way to read the configuration file is :
    //        FileInputStream fis = new FileInputStream("jdbc.properties");
    //        FileInputStream fis = new FileInputStream("src\\jdbc1.properties");
    //        pros.load(fis);

    // The second way to read the configuration file is : Use ClassLoader
    // By default, the configuration file is recognized as : At present module Of src Next 
    ClassLoader classLoader = ClassLoaderTest.class.getClassLoader();
    InputStream is = classLoader.getResourceAsStream("jdbc1.properties");
    pros.load(is);

    String user = pros.getProperty("user");
    String password = pros.getProperty("password");
    System.out.println("user = " + user + ",password = " + password);
}

Reflection application 1 : Create an object of a runtime class

The code for

Class<Person> clazz = Person.class;

Person obj = clazz.newInstance();
System.out.println(obj);

explain

newInstance(): Call this method , Create the object of the corresponding runtime class . The constructor that internally calls the null parameter of the runtime class .

You want this method to create runtime class objects normally , requirement :

  1. Runtime classes must provide constructors for null arguments
  2. The constructor of the null parameter has enough access rights . Usually , Set to public.

stay javabean You are required to provide a public The empty parameter constructor of . reason :

  1. Easy to pass through reflection , Create an object of a runtime class
  2. When subclasses inherit this runtime class , Default call super() when , Ensure that the parent class of this constructor

Reflection application 2 : Get the complete structure of the runtime class

We can do it through reflection , Gets all the properties in the corresponding runtime class 、 Method 、 Constructors 、 Parent class 、 Interface 、 Generics of the parent class 、 package 、 annotation 、 Abnormal etc. ....

get attribute

@Test
public void test1(){

    Class clazz = Person.class;

    // Get attribute structure 
    //getFields(): Gets the current runtime class and its parent class declared as public Properties of access rights 
    Field[] fields = clazz.getFields();
    for(Field f : fields){
        System.out.println(f);
    }
    System.out.println();

    //getDeclaredFields(): Gets the properties declared in the current runtime class .( Does not contain properties declared in the parent class 
    Field[] declaredFields = clazz.getDeclaredFields();
    for(Field f : declaredFields){
        System.out.println(f);
    }
}

Access method

@Test
public void test1(){

    Class clazz = Person.class;

    //getMethods(): Gets the current runtime class and its parent class declared as public The method of authority 
    Method[] methods = clazz.getMethods();
    for(Method m : methods){
        System.out.println(m);
    }
    System.out.println();
    //getDeclaredMethods(): Gets the method declared in the current runtime class .( Does not contain methods declared in the parent class 
    Method[] declaredMethods = clazz.getDeclaredMethods();
    for(Method m : declaredMethods){
        System.out.println(m);
    }
}

Get the constructor

@Test
public void test1(){

    Class clazz = Person.class;
    //getConstructors(): Get the current class declaration in the runtime public Constructor 
    Constructor[] constructors = clazz.getConstructors();
    for(Constructor c : constructors){
        System.out.println(c);
    }

    System.out.println();
    //getDeclaredConstructors(): Gets the constructor declared in the current runtime class 
    Constructor[] declaredConstructors = clazz.getDeclaredConstructors();
    for(Constructor c : declaredConstructors){
        System.out.println(c);
    }
}

Get the parent class

@Test
public void test2(){
    Class clazz = Person.class;

    Class superclass = clazz.getSuperclass();
    System.out.println(superclass);
}

Gets the generic parent class of the runtime class

@Test
public void test3(){
    Class clazz = Person.class;

    Type genericSuperclass = clazz.getGenericSuperclass();
    System.out.println(genericSuperclass);
}

Gets the generic of the parent class with generics of the runtime class

@Test
public void test4(){
    Class clazz = Person.class;

    Type genericSuperclass = clazz.getGenericSuperclass();
    ParameterizedType paramType = (ParameterizedType) genericSuperclass;
    // Get generic type 
    Type[] actualTypeArguments = paramType.getActualTypeArguments();
    //        System.out.println(actualTypeArguments[0].getTypeName());
    System.out.println(((Class)actualTypeArguments[0]).getName());
}

Get the interface implemented by the runtime class

@Test
public void test5(){
    Class clazz = Person.class;

    Class[] interfaces = clazz.getInterfaces();
    for(Class c : interfaces){
        System.out.println(c);
    }

    System.out.println();
    // Get the interface implemented by the parent class of the runtime class 
    Class[] interfaces1 = clazz.getSuperclass().getInterfaces();
    for(Class c : interfaces1){
        System.out.println(c);
    }

}

Get the package where the runtime class is located

@Test
public void test6(){
    Class clazz = Person.class;

    Package pack = clazz.getPackage();
    System.out.println(pack);
}

Get the annotation of the runtime class declaration

@Test
public void test7(){
    Class clazz = Person.class;

    Annotation[] annotations = clazz.getAnnotations();
    for(Annotation annos : annotations){
        System.out.println(annos);
    }
}

Reflection application 3 : Call the specified structure of the runtime class

Call the specified property

@Test
public void testField1() throws Exception {
    Class clazz = Person.class;

    // Create an object of a runtime class 
    Person p = (Person) clazz.newInstance();

    //1. getDeclaredField(String fieldName): Gets the property of the specified variable name in the runtime class 
    Field name = clazz.getDeclaredField("name");

    //2. Ensure that the current property is accessible 
    name.setAccessible(true);
    //3. obtain 、 Set the value of this property of the specified object 
    name.set(p,"Tom");

    System.out.println(name.get(p));
}

Call the specified method

 @Test
    public void testMethod() throws Exception {

        Class clazz = Person.class;

        // Create an object of a runtime class 
        Person p = (Person) clazz.newInstance();

        /*
        1. Get a specified method 
        getDeclaredMethod(): Parameters 1 : Indicates the name of the method obtained    Parameters 2: Indicates the formal parameter list of the method to be obtained 
         */
        Method show = clazz.getDeclaredMethod("show", String.class);
        //2. Ensure that the current method is accessible 
        show.setAccessible(true);

        /*
        3.  Calling method invoke(): Parameters 1: The caller of the method    Parameters 2: Arguments that assign values to method parameters 
        invoke() The return value is the return value of the method called in the corresponding class .
         */
        Object returnValue = show.invoke(p,"CHN"); //String nation = p.show("CHN");
        System.out.println(returnValue);

        System.out.println("************* How to call static methods *****************");

        // private static void showDesc()

        Method showDesc = clazz.getDeclaredMethod("showDesc");
        showDesc.setAccessible(true);
        // If the method in the runtime class called does not return a value , Then this invoke() return null
//        Object returnVal = showDesc.invoke(null);
        Object returnVal = showDesc.invoke(Person.class);
        System.out.println(returnVal);//null

    }

Call the specified constructor

@Test
public void testConstructor() throws Exception {
    Class clazz = Person.class;

    //private Person(String name)
    /*
    1. Get the specified constructor 
    getDeclaredConstructor(): Parameters : Indicates the parameter list of the constructor 
     */

    Constructor constructor = clazz.getDeclaredConstructor(String.class);

    //2. Ensure that this constructor is accessible 
    constructor.setAccessible(true);

    //3. Call this constructor to create an object of the runtime class 
    Person per = (Person) constructor.newInstance("Tom");
    System.out.println(per);

}

Reflection application 4 : A dynamic proxy

The principle of proxy mode

Use a proxy to wrap the object , Then replace the original object with the proxy object . Any call to the original object is made through a proxy . The proxy object determines whether and when method calls are transferred to the original object .

Static proxy

give an example

Realization Runnable Interface method to create multithreading .

Class MyThread implements Runnable{} // Equivalent to the surrogate class 
Class Thread implements Runnable{} // Equivalent to a proxy class 

main(){
    MyThread t = new MyThread();
    Thread thread = new Thread(t);
    thread.start();// Start thread ; Calling thread's run()
}

Disadvantages of static proxies

  • ① Both the proxy class and the target object class are determined during compilation , Not conducive to the expansion of the program .
  • ② Each proxy class can only serve one interface , In this way, there must be too many agents in program development .

A dynamic proxy

Dynamic proxy refers to the method that clients call other objects through proxy class , And it is to create the proxy object of the target class dynamically when the program is running .

The realization of dynamic agent

Question 1 : According to the proxy class loaded into memory , Create a proxy class and its objects dynamically .
( adopt Proxy.newProxyInstance() Realization )
Question two : When a method is called through an object of a proxy class a when , How to dynamically call the method with the same name in the proxy class a.
( adopt InvocationHandler Interface implementation class and its methods invoke())

Example

interface Human{

    String getBelief();

    void eat(String food);

}
// Surrogate class 
class SuperMan implements Human{


    @Override
    public String getBelief() {
        return "I believe I can fly!";
    }

    @Override
    public void eat(String food) {
        System.out.println(" I love eating " + food);
    }
}
class HumanUtil{

    public void method1(){
        System.out.println("==================== General method one ====================");

    }

    public void method2(){
        System.out.println("==================== General method 2 ====================");
    }

}
class ProxyFactory{
    // Call this method , Returns an object of a proxy class . Solve problem one 
    public static Object getProxyInstance(Object obj){//obj: Object of the proxied class 
        MyInvocationHandler handler = new MyInvocationHandler();

        handler.bind(obj);

        return Proxy.newProxyInstance(obj.getClass().getClassLoader(),obj.getClass().getInterfaces(),handler);
    }

}
class MyInvocationHandler implements InvocationHandler{

    private Object obj;// You need to use the object of the proxy class to assign the value 

    public void bind(Object obj){
        this.obj = obj;
    }

    // When we proxy objects of classes , Calling method a when , The following methods will be called automatically :invoke()
    // The method to be executed by the proxy class a The function of is declared in invoke() in 
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        HumanUtil util = new HumanUtil();
        util.method1();

        //method: The method called for the proxy class object , This method is also used as the method to be called by the proxy class object 
        //obj: Object of the proxied class 
        Object returnValue = method.invoke(obj,args);

        util.method2();

        // The return value of the above method is taken as the current class invoke() The return value of .
        return returnValue;

    }
}
public class ProxyTest {

    public static void main(String[] args) {
        SuperMan superMan = new SuperMan();
        //proxyInstance: Object of proxy class 
        Human proxyInstance = (Human) ProxyFactory.getProxyInstance(superMan);
        // When a method is called through a proxy class object , The method with the same name in the proxy class will be called automatically 
        String belief = proxyInstance.getBelief();
        System.out.println(belief);
        proxyInstance.eat(" Sichuan Mala ");

        System.out.println("*****************************");

        NikeClothFactory nikeClothFactory = new NikeClothFactory();

        ClothFactory proxyClothFactory = (ClothFactory) ProxyFactory.getProxyInstance(nikeClothFactory);

        proxyClothFactory.produceCloth();

    }
}

It's hard to reflect , Make a special article to understand

版权声明
本文为[Want to exchange steamed stuffed bun for thesis]所创,转载请带上原文链接,感谢

Scroll to Top