Java reflection mechanism, java primary project case

Posted by angeljyt on Wed, 08 Sep 2021 00:33:56 +0200

How to reduce the coupling and improve the adaptability of the code?

It is implemented through the interface, but if the interface needs to use the new keyword, the coupling problem will occur again

for instance:

 /**
/**
 * @ClassName: TestReflection 
 * @Model : (Module name)
 * @Description: Use reflection to reduce coupling (through interface)
 * @author Administrator 
 * @date 2017 June 2, 2005 5:09:38 PM 
 */
public class TestReflection {

    /**
    /**
     * main (Here is a sentence to describe the function of this method) 
     * @param args
     * void 
     * @ModifiedPerson Administrator
     * @date 2017 June 2, 2005 5:09:38 PM 
     */
    public static void main(String[] args) {

        //Common writing, using the New keyword
        ITest iTest = createITest("ITestImpl1");
        iTest.testReflect();
        ITest iTest2 = createITest("ITestImpl2");
        iTest2.testReflect();
        
    }

    /**
    * createITest Normally, use the New keyword, but suppose 1000 different itests need to be created, do you plan to write 1000 if statements to return different ITest objects?
    * @param name
    * @return
    * ITest 
    * @ModifiedPerson Administrator
    * @date 2017 June 2, 2005 5:32:21 PM
     */
    public static ITest createITest(String name){
        
        if (name.equals("ITestImpl1")) {
            return new ITestImpl1();
        } else if(name.equals("ITestImpl2")){
            return new ITestImpl2();
        }
    
        return null;
    }

}


interface ITest{
    public void testReflect();
}

class ITestImpl1 implements ITest{

    /* (non-Javadoc)
    * <p>Title: test</p> 
    * <p>Description: </p>  
    * @see ITest#test()
    */
    @Override
    public void testReflect() {

         System.out.println("I am ITestImpl1 !");
    }
}

class ITestImpl2 implements ITest{

    /* (non-Javadoc)
    * <p>Title: testReflect</p> 
    * <p>Description: </p>  
    * @see ITest#testReflect()
    */
    @Override
    public void testReflect() {

        System.out.println("I am ITestImpl2 !");
    }
    
} 

Suppose 1000 different itests need to be created, do you plan to write 1000 if statements to return different ITest objects?

What if you use a reflection mechanism?

 /**
/**
 * @ClassName: TestReflection 
 * @Model : (Module name)
 * @Description: Use reflection to reduce coupling (through interface)
 * @author Administrator 
 * @date 2017 June 2, 2005 5:09:38 PM 
 */
public class TestReflection {

    /**
    /**
     * main (Here is a sentence to describe the function of this method) 
     * @param args
     * void 
     * @ModifiedPerson Administrator
     * @date 2017 June 2, 2005 5:09:38 PM 
     */
    public static void main(String[] args) {
        //Common writing, using the New keyword
        ITest iTest = createITest("ITestImpl1");
        iTest.testReflect();
        ITest iTest2 = createITest("ITestImpl2");
        iTest2.testReflect();
        
        //Use reflection mechanism
        ITest iTest3 = createITest2("ITestImpl1");
        iTest3.testReflect();
        ITest iTest4 = createITest2("ITestImpl2");
        iTest4.testReflect();
        
    }

    /**
    * createITest Normally, use the New keyword, but suppose 1000 different itests need to be created, do you plan to write 1000 if statements to return different ITest objects?
    * @param name
    * @return
    * ITest 
    * @ModifiedPerson Administrator
    * @date 2017 June 2, 2005 5:32:21 PM
     */
    public static ITest createITest(String name){
        
        if (name.equals("ITestImpl1")) {
            return new ITestImpl1();
        } else if(name.equals("ITestImpl2")){
            return new ITestImpl2();
        }
    
        return null;
    }
    
    /**
    * createITest2 Use reflection mechanism: when 1000 different itests need to be created, you don't need to create ITest objects for each
    * @param name
    * @return
    * ITest 
    * @ModifiedPerson Administrator
    * @date 2017 5:34:55 PM, June 2, 2014
     */
    public static ITest createITest2(String name){
        try {
            Class<?> class1 = Class.forName(name);
            ITest iTest = (ITest) class1.newInstance();
            return iTest;
        } catch (ClassNotFoundException e) {

            e.printStackTrace();
        } catch (InstantiationException e) {

            e.printStackTrace();
        } catch (IllegalAccessException e) {

            e.printStackTrace();
        }
        
        return null;
        
    }

}


interface ITest{
    public void testReflect();
}

class ITestImpl1 implements ITest{

    /* (non-Javadoc)
    * <p>Title: test</p> 
    * <p>Description: </p>  
    * @see ITest#test()
    */
    @Override
    public void testReflect() {

         System.out.println("I am ITestImpl1 !");
    }
}

class ITestImpl2 implements ITest{

    /* (non-Javadoc)
    * <p>Title: testReflect</p> 
    * <p>Description: </p>  
    * @see ITest#testReflect()
    */
    @Override
    public void testReflect() {

        System.out.println("I am ITestImpl2 !");
    }
    
} 

The principle of decoupling using reflection mechanism is to create objects "dynamically" by using reflection mechanism: pass in the package name of Hero class to createITest() method. The class name loads the specified class, and then instantiates the object

3, Understand Class and Class types

To understand reflection, we must first understand the Class class, because the Class class is the basis of reflection implementation.

3.1 are classes objects

In the object-oriented world, everything is an object. An object is an instance of a class, so a class is an instance object of a java.lang.Class class, and class is the class of all classes (This is a class named Class). Class is a class type, that is, the type of a class.

3.2 acquisition of class objects

For ordinary objects, we create an object directly through new.

Student sdutent = new Student();

However, the object of Class is a Class and cannot be created through new. The source code of Class is described as follows:

/*
     * Private constructor. Only the Java Virtual Machine creates Class objects.
     * This constructor is not used and prevents the default constructor being
     * generated.
     */
    private Class(ClassLoader loader) {
        // Initialize final field for classLoader.  The initialization value of non-null
        // prevents future JIT optimizations from assuming this final field is null.
        classLoader = loader;
    } 

The constructor is private. Only the Java virtual machine (JVM) can create a Class object, not a new Class object like an ordinary Class. You can only get a Class object from an existing Class (three methods):

The first method
Class<?> cls = Class.forName("com.example.student");//forName (package name. Class name)
Student s1 = (Student)cls.newInstance(); 
  1. Find and load the specified class through the JVM
  2. Call the newInstance() method, let the loaded class create the corresponding instance in memory, and assign the instance to s1
The second method
Student s = new Student;    
Class<?> cls = s.getClass;
Student s2 = (Student)cls.newInstance(); 
  1. Create a new instance of Student in memory, and the object s references the memory address
  2. Object s calls the getClass() method to return the Class object corresponding to object s
  3. Call the newInstance() method, let the Class object create an instance of the object in memory, and let s2 reference the memory address of the instance
The third method
Class<?> cls = Student.Class();
Student s3 = (Student)cls.newInstance(); 
  1. Gets the Class object of the specified type. Here is Student
  2. Call the newInstance() method, let the Class object create the corresponding instance in memory, and let s3 reference the memory address of the instance
be careful:
  • The cls.newInstance() method returns a generic T, which we need to convert to the Student class
  • cls.newInstance() returns the parameterless constructor object of Student class by default
  • The class loaded by the reflection mechanism must have a parameterless constructor. Otherwise, an exception will be thrown

The difference between creating a class through class type and creating a class through new is that class type creates a dynamically loaded class.

4, Dynamic loading class

Program execution is divided into compiler and runtime. Loading a class at compilation time is called static loading class, and loading a class at runtime is called dynamic loading class. The following is an example:

Now, instead of IDE tools, use Notepad to write classes. This is to facilitate us to manually compile and run a class by using cmd command line, so as to better understand the difference between dynamically loaded classes and statically loaded classes.

First write First.java

class First
{
    public static void main(String[] args)
    {
        if ("Word".equals(args[0]))
        {   
            // Statically loaded classes, loaded at compile time
            Word w = new Word();
            w.start();
        }
        if ("Excel".equals(args[0]))
        {
            Excel e = new Excel();
            e.start();
        }
    }
} 

Then enter cmd to compile First.java

Because the two classes of Word and Excel in new are not compiled, an error is reported. This is the disadvantage of statically loading classes, that is, all possible classes must be loaded during compilation. What we want to achieve is to load which class is used during runtime. The following is improved by dynamically loading classes.

Improved class: FirstBetter.java

class FirstBetter
{   
    public static void main(String[] args)
    {
            try
        {
            // Dynamically loaded classes, loaded at run time
            Class c = Class.forName(args[0]);
            // Create the class object through the class type
            FirstAble oa = (FirstAble)c.newInstance();
            oa.start();
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
    }   
} 

Here, a class named args[0] is dynamically loaded, and args[0] is the first parameter input to the main method at runtime. If you enter Word, Word.java will be loaded. At this time, you need to create Word.java under the same path as FirstBetter.java; Similarly, if you enter Excel, you need to load Excel.java. Among them, FirstAble is an interface. The dynamically loaded classes such as Word and Excel implement FirstAble, which reflects the idea of polymorphism. This idea of dynamic loading and polymorphism can decouple specific functions from code, that is, if you want to add a function at any time (such as Word and Excel, I want PPT), you can dynamically add it without changing the original code.

The FirstAble interface is as follows:

interface FirstAble
{
    public void start();
} 

Word class:

class Word implements FirstAble
{
    public void start()
    {
        System.out.println("word...starts...");
    }
} 

Compile and run the above classes in order.

5, Get class information

A class usually contains attributes and methods. It obtains the class's construction methods, member methods, member variables, modifications (of methods and variables) through reflection.

5.1 get class constructor

What are included in constructors: constructor parameters

The constructor of a class is an object, which is an object of java.lang.reflect.Constructor, so we obtain this information through the methods encapsulated in java.lang.reflect.Constructor.

1. Get a constructor separately

It is implemented through the following methods of Class:

  • public Constructor getDeclaredConstructor(Class<?>… parameterTypes) / / returns a specific constructor (regardless of public and non-public attributes) according to the parameters of the constructor
  • public Constructor getConstructor(Class<?>… parameterTypes) / / returns a concrete constructor with public attribute according to the parameters of the constructor
  • Parameter parameterTypes is a list of class types for constructor parameter classes.

For example, class A has the following constructor:

public A(String a, int b) {
    // code body
} 

Then you can:

Constructor constructor = a.getDeclaredConstructor(String.class, int.class); 

To get this constructor.

2. Get all constructors

It is implemented through the following methods of Class:

  • Constructor getdeclaraedconstructors() returns all constructor arrays in this class (regardless of public and non-public attributes)
  • Constructor getConstructors() returns an array of all constructors with public attribute

This can be achieved by the following steps:

1. Given an object, get the class type of its class

Class c = obj.getClass(); 

2. Get all constructors of this class and put them in an array

Constructor[] constructors = c.getDeclaredConstructors(); 

3. Traverse the constructor array to obtain a constructor

for (Constructor constructor : constructors) 

4. Get the class type array of constructor parameter types

Class[] paramTypes = constructor.getParameterTypes(); 

5. Traverse the class type array of the parameter class to get the class type class1 of a parameter

for (Class class1 : paramTypes) 

6. Get the type name of the parameter

String paramName = class1.getName(); 

example:

private static void forName2GetConstructor() {
        try {
            //The first method: forName()
            Class<?> class1 = Class.forName("com.zyt.reflect.StudentInfo");
            
            Constructor<?>[] constructors = class1.getDeclaredConstructors();
            for (Constructor<?> constructor : constructors) {
                System.out.print("Construction method:"+constructor.getName()+" Parameter type:");
                Class<?>[] parameterTypes = constructor.getParameterTypes();
                for (Class<?> class2 : parameterTypes) {
                    System.out.print(class2.getName()+" , ");
                }
                System.out.print("\n");
            }
            
            //Call constructor
            Constructor<?> constructor = class1.getDeclaredConstructor(String.class, String.class, int.class);
            StudentInfo instance = (StudentInfo) constructor.newInstance("Zhang San", "male", 18);
            System.out.println("Call constructor == "+instance.getName()+","+instance.getScore());
            
            
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    } 

5.2 get class member methods

What are included in member methods: return value type + method name + parameter type

In Java, the member method of a class is also an object, which is an object of java.lang.reflect.Method, so we obtain this information through the methods encapsulated in java.lang.reflect.Method

1. Get a method separately
  • Method getMethod(String name, Class[] params) returns a specific method with public attribute according to the method name and parameters
  • Method getdeclaraedmethod (string name, class [] params) returns a specific method (regardless of public and non-public attributes) according to the method name and parameters
  • The two parameters are the method name and the class type list of the method parameter class.

For example, class A has the following method:

public void print(String a, int b) {
    // code body
} 

Now that you know that a has an object a, you can:

Class c = a.getClass();
Method method = c.getDeclaredMethod("print", String.class, int.class); 

To get this method.

How to call the obtained method

How to call this Method after obtaining the Method is implemented through the following methods of the Method class:

public Object invoke(Object obj, Object... args) 

The two parameters are the object to which the method belongs and the parameters required by the method, or use the above example to illustrate, through:

method.invoke(a, "hello", 10); 

And through normal calls:

a.print("hello", 10); 

The effect is exactly the same. This is the reflection of the method. The invoke() method can call the method with its object as a parameter, which is completely opposite to the normal situation.

2. Gets information about all member methods in the class
  • Method[] getMethods() returns an array of all methods with public attribute
  • Method[] getDeclaredMethods() returns an array of all methods in this class (regardless of public and non-public attributes)
be careful:

getMethods(): used to obtain the member methods of all public modification domains of the class, including the public methods inherited from the parent class and the public methods implementing the interface;

getDeclaredMethods(): used to obtain all member methods and implemented interface methods defined in the current class, excluding methods inherited from the parent class.

You can check the explanation of the development document:

getMethods() - Returns an array containing Method objects for all public methods for the class C represented by this Class. 

&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp; Methods may be declared in C, the interfaces it implements or in the superclasses of C. 

&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp; The elements in the returned array are in no particular order. 

getDeclaredMethods() - Returns a Method object which represents the method matching the specified name and parameter types 

&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;  that is declared by the class represented by this Class. 

Therefore, in the method get of the sample code_ Reflection_ In method (...), the ReflectionTest class inherits the Object class, implements the actionPerformed method, and defines the following member methods:

[external chain picture transfer failed. The source station may have anti-theft chain mechanism. It is recommended to save the picture and upload it directly (img-g6muhzrh-163103844352)( https://user-gold-cdn.xitu.io/2018/8/23/16565e76f3d05bef?imageView2/0/w/1280/h/960/ignore -error/1)]

The results after execution of these two statements are different:

a. Method[] methods = temp.getDeclaredMethods() after execution, the results are as follows:

[external chain picture transfer failed. The source station may have anti-theft chain mechanism. It is recommended to save the picture and upload it directly (img-kgh1hsxw-163103844354)( https://user-gold-cdn.xitu.io/2018/8/23/16565e76f395fe00? imageView2/0/w/1280/h/960/ignore-error/1)]

b. After Method[] methods = temp.getMethods() is executed, the results are as follows:

[external chain picture transfer failed. The source station may have anti-theft chain mechanism. It is recommended to save the picture and upload it directly (img-qfolfxno-163103844357)( https://user-gold-cdn.xitu.io/2018/8/23/16565e76f3e9ef96? imageView2/0/w/1280/h/960/ignore-error/1)]

Method class:

public invoke( obj,                       ... args) 

Calls the underlying Method represented by this Method object on the specified object with the specified parameters. Individual parameters are automatically unpacked to match the basic formal parameters. The basic parameters and reference parameters obey the Method call conversion as needed.

  • If the underlying method is static, the specified obj parameter can be ignored. The parameter can be null.

  • If the shape parameter required by the underlying method is 0, the length of the args array provided can be 0 or null.

  • If the underlying method is an instance method, dynamic method lookup is used to call it, which is recorded in section 15.12.4.4 of Java Language Specification, Second Edition; This is especially true when overriding the runtime type based on the target object.

  • If the underlying method is static and the class that declares the method has not been initialized, it will be initialized.

  • If the method completes normally, return the value returned by the method to the caller; If the value is a basic type, wrap it appropriately in the object first. However, if the type of the value is a set of basic types, the array elements are not wrapped in the object; In other words, an array of primitive types is returned. If the return type of the underlying method is void, the call returns null.

Parameters:

obj- calls the object of the underlying method.

args - parameter for method call

return:

Use the args parameter to assign the result of the method represented by the object on obj   if you want to obtain the information of all but not a single member method in the class, you can do it in the following steps:

1. Given an object, get the class type of its class

last

The knowledge points involved in the article have been sorted into materials, and videos have been recorded for everyone to download and study. I am full of sincerity. I hope to help friends who develop in this industry, spend less time looking for materials in forums, blogs and other places, and really spend limited time on learning, so I share these materials. I believe that for friends who have worked and encountered technical bottlenecks, you must have the content you need in this material.

CodeChina open source project: [analysis of Java interview questions of front-line large manufacturers + core summary learning notes + latest explanation Video]

This should be done even more when rewriting.

  • If the underlying method is static and the class that declares the method has not been initialized, it will be initialized.

  • If the method completes normally, return the value returned by the method to the caller; If the value is a basic type, wrap it appropriately in the object first. However, if the type of the value is a set of basic types, the array elements are not wrapped in the object; In other words, an array of primitive types is returned. If the return type of the underlying method is void, the call returns null.

Parameters:

obj- calls the object of the underlying method.

args - parameter for method call

return:

Use the args parameter to assign the result of the method represented by the object on obj   if you want to obtain the information of all but not a single member method in the class, you can do it in the following steps:

1. Given an object, get the class type of its class

last

The knowledge points involved in the article have been sorted into materials, and videos have been recorded for everyone to download and study. I am full of sincerity. I hope to help friends who develop in this industry, spend less time looking for materials in forums, blogs and other places, and really spend limited time on learning, so I share these materials. I believe that for friends who have worked and encountered technical bottlenecks, you must have the content you need in this material.

CodeChina open source project: [analysis of Java interview questions of front-line large manufacturers + core summary learning notes + latest explanation Video]

Topics: Java Back-end Programmer