Reflection from 0 to getting started

Personal public number: not a bald programmer, Xiao Li.
Focus on Java content, welcome to leave a message
There are many articles in the article, so it is suggested to collect them

reflex

Java is divided into compile time and run time

Compilation method description:

  1. Static compilation: determines the type & bound object at compile time. Such as the common use of new keyword to create objects
  2. Dynamic compilation: determines the type & binding object at run time. Dynamic compilation embodies the flexibility and polymorphism of Java & reducing the coupling between classes

When we start to learn in the future, we should start to learn knowledge points around the following questions.

  • What is it?
  • What is its function?
  • What are its advantages? What are the disadvantages?
  • How do we use it?
  • What is its principle?

Next, I will explain reflection in three chapters: reflection from 0 to introduction, reflection from introduction to mastery and reflection application

What is reflex

Reflection is one of the features of Java. It allows running Java programs to obtain their own information and manipulate the internal properties of classes or objects.

Oracle's official interpretation of reflection is:

Reflection enables Java code to discover information about the fields, methods and constructors of loaded classes, and to use reflected fields, methods, and constructors to operate on their underlying counterparts, within security restrictions.

The API accommodates applications that need access to either the public members of a target object (based on its runtime class) or the members declared by a given class. It also allows programs to suppress default reflective access control.

Through reflection, we can get the member and member information of each type in the assembly when the program is running. The type of objects we usually use new to create is determined at compile time. Java reflection can dynamically create objects and call their properties. The type of such objects is unknown at compile time. So we can create objects through reflection mechanism, even if the object type is unknown at compile time.

The core of reflection is that the JVM will dynamically load classes, call methods and access properties at run time. It does not need to know who the running objects are at compile time.

Java reflection mainly provides the following functions:

  • Judge the class of any object at runtime
  • Construct an object of any class at run time
  • Judge the member variables and methods of any class at runtime
  • Calling a method of any object at run time

We can get any class, object, variable, method and so on you want at runtime.

Note: Reflection operates at run time, not compile time.

Main use of reflection

  • Implement design patterns such as factory pattern and agent pattern.
  • Database connection for JDBC.
  • Spring, Struts and other frameworks use reflection to dynamically load the objects to be loaded at runtime.
  • Tips for IDE development tools, such as when we enter an object or class and want to call its properties or methods, the compiler will automatically list its properties or methods by clicking the dot.

Advantages and disadvantages of reflection

Advantage:

  • It can judge the type and load the dynamic class during the running period.
  • Improve code flexibility. For example: JDBC can dynamically connect to a database.

Disadvantages:

  • Performance problems

    Because reflection includes dynamic types, the JVM cannot optimize the code. Therefore, the efficiency of reflection operations is much slower than those of direct calls. So try to avoid using reflection in frequently executed code or programs with high performance requirements.

    (reflection is about 50-100 times slower than direct call, but it needs to be executed 1 million times before I can feel it.)

  • Safety restriction

    Using reflection technology requires the program to run in an environment without security restrictions.

  • Internal leakage

    Reflection allows code to perform operations that are not normally allowed (access to private properties or methods), so using reflection can lead to unexpected side effects -- code has functional errors, reducing portability. Reflection breaks the abstraction of the code, so when the platform changes, the behavior of the code may change.

Question: Java reflection can access and modify private member variables. Is it meaningful to encapsulate it as private?

Since thieves can visit and move smuggled furniture, does it make sense to seal it as a security door? This is the same principle, and Java provides us with a security management mechanism -- Security Manager from the application layer. Each Java application can have its own security manager, which will check the access rights of the resources to be protected and other specified operation rights at the run-time to protect the system from malicious operation attacks, so as to achieve the system's security policy.

So when reflection is used, there are internal security controls. If the security settings prohibit these, the reflection mechanism cannot access private members.

Specific use

Class

Class holds the runtime information of the corresponding type. When a java program runs, the Java virtual machine maintains a java.lang.Class object for all types. The class object holds all runtime information about the object.

Get Class

Then how can we get the desired Class, look this Code

    public static void main(String[] args) {
        // Method 1: Object.getClass()
        // The getClass() method of the Object Class returns a Class instance
        String name = "Not a bald little Li programmer";
        Class<?> classType = name.getClass();
        System.out.println("Object.getClass() classType: " + classType);

        // Mode 2: T.Class
        // T is any Java type
        Class<?> classType2 = String.class;
        System.out.println("T.Class classType: " + classType2);

        // Mode 3: Class.forName
        try {
            Class<?> classType3 = Class.forName("java.lang.String");
            System.out.println("Class.forName classType: " + classType2);
            // ClassNotFoundException exception will be thrown if no class is found according to className
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

Three methods of obtaining Class

  • getClass()
  • T.class
  • Class.forName

These three usages need to be used flexibly according to specific scenarios. For example, when JDBC obtains the database type of the connection, it uses Class.forName("class path").

Get parent Class

Get the Class of the parent Class through getSuperclass(), as shown in the following example:

Class<?> superclass = Integer.class.getSuperclass();
System.out.println(superclass);
System.out.println(superclass.getSuperclass());
System.out.println(superclass.getSuperclass().getSuperclass());
System.out.println(superclass.getSuperclass().getSuperclass().getSuperclass());

Operation result

class java.lang.Number
class java.lang.Object
null
Exception in thread "main" java.lang.NullPointerException

You can see that the parent class of Integer is Number, and the parent class of Number is Object, so there is no parent class for Object, so an exception of null pointer will be thrown after null.

Summary

If you get the desired Class, you can get all its information.

Before you get the information you want, you may want to know something about it.

The difference between methods with and without "Declared"

  1. Method s without "Declared" support fetching fields, methods and constructors including inheritance, public.
  2. Method s with "Declared" support fetching fields, methods and constructors including all constructors of the current class (including public and private, excluding inheritance).

Field

Get Field

How to obtain field information through a Class instance. The Class class provides the following methods to get fields:

  • Field getField(String name): get a public field according to the field name
  • Field[] getFields(): get all public fields
  • Field getDeclaredField(String name): get a field of the current class according to the field name
  • Field[] getDeclaredFields(): get all fields of the current class

show me code

public class FiledTest1 {
    public static void main(String[] args) throws NoSuchFieldException {
        Class stdClass = Student.class;
        // Get public field "score"
        System.out.println(stdClass.getField("score"));
        // Get the continued public field "name"
        System.out.println(stdClass.getField("name"));
        // Get private field "grade"
        System.out.println(stdClass.getDeclaredField("grade"));
    }
}

class Student extends Person{
    public int score;
    private int grade;
}

class Person{
    public String name;
}

Operation result:

public int com.javastudy.reflection.Fields.Student.score
public java.lang.String com.javastudy.reflection.Fields.Person.name
private int com.javastudy.reflection.Fields.Student.grade

Get Field information

A file object contains all the information of a field:

  • getName(): returns the field name, for example: name;
  • getType(): returns the field type, which is also a class instance, for example: String.class
  • getModifiers(): returns the modifier of a field. It is an int. different bit s represent different meanings.

The java.lang.reflect.Method.getModifiers() method returns the Java language modifiers for the method represented by this Method object, as an integer. The Modifier class should be used to decode the modifiers.

The getmodifiers() method returns the Java language modifier of the method represented by the method object as an integer. Modifiers should be used to decode modifiers.

public class FieldTest2 {

    private final String name = "Not a bald little Li programmer";

    public static void main(String[] args) throws NoSuchFieldException {
        Class c = FieldTest2.class;
        Field field = c.getDeclaredField("name");
        int mod = field.getModifiers();
        System.out.println("name: " + field.getName());
        System.out.println("type: " + field.getType());
        System.out.println("final: " + Modifier.isFinal(mod));
        System.out.println("public: " + Modifier.isPublic(mod));
        System.out.println("protected: " + Modifier.isProtected(mod));
        System.out.println("private: " + Modifier.isPrivate(mod));
        System.out.println("static: " + Modifier.isStatic(mod));
    }
}

Operation result:

name: name
type: class java.lang.String
final: true
public: false
protected: false
private: true
static: false

Get field value

We get the Field. We should get the corresponding value of the Field through the Field. Let's use the above example to get the name value.

public class FieldTest3 {

    private final String name = "Not a bald little Li programmer";

    public static void main(String[] args) throws Exception {
        Object object = new FieldTest3();
        Class c = FieldTest3.class;
        Field field = c.getDeclaredField("name");
        Object value = field.get(object);
        System.out.println(value);
    }
}

Operation result:

Not a bald little Li programmer

Let's get() to get the value of the Field. Let's take a look at the following example:

public class FieldTest4 {

    public static void main(String[] args) throws Exception { 
        Object animal = new Animal("Not a bald little Li programmer Animal111");
        Class c = Animal.class;
        Field field = c.getDeclaredField("name");
        Object value = field.get(animal);
        System.out.println(value);
//        Animal animal = new Animal();
//        animal.testFiled();
    }
}

class Animal {
    private String name;

    public Animal() {
    }

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

    public void testFiled() throws Exception {
        Object animal = new Animal("Not a bald little Li programmer Animal222");
        Class c = Animal.class;
        Field field = c.getDeclaredField("name");
        Object value = field.get(animal);
        System.out.println(value);
    }
}

Operation result:

Exception in thread "main" java.lang.IllegalAccessException: Class com.javastudy.reflection.Fields.FieldTest4 can not access a member of class com.javastudy.reflection.Fields.Animal with modifiers "private"

WTF? There is an exception. Xiaoli, are you playing with me? You can do it for the first time, and you will be prompted for no permission for the second time. Can you get the value I want. Of course, can I show you bald.

We just need to add the following code to the previous step of filed.get(). Whether you are public or private

field.setAccessible(true);

Let's think about why we can access it for the first time without the above code?

Because it's accessed in your own class, just think about yourself. You have a nose and two ears. They are private. You can touch them and pick them up at will. But when others want to touch them, they must have your consent (setAccessible(true)). So understand the code just now, and you will understand. If you don't understand, you can open the above two comments:

Animal animal = new Animal();
animal.testFiled();

Operation result:

Not bald Li programmer 222

Set field value

Through the Field instance, you can not only get the Field value of the specified instance, but also set the Field value.

Set the Field value through the set method of Field.

// The first parameter is the specified instance
// The second parameter is the value to be modified
void set(Object obj, Object value)

The sample code is as follows:

public class FieldTest5 {
    public static void main(String[] args) throws Exception {
        Teacher teacher = new Teacher("Not a bald little Li programmer");
        Class c = teacher.getClass();
        Field field = c.getDeclaredField("name");
        field.setAccessible(true);
        field.set(teacher,"Xiao Li is not bald");
        System.out.println(field.get(teacher));
    }
}
class Teacher{
    private String name;

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

    public String getName() {
        return name;
    }
}

Print results:

Xiao Li is not bald

It's easy for me not to be bald. It's time to ask questions

What is the role of Field in the obj parameters of get and set?

Answer: we can learn from the api comments that OBJ can pass null when these two methods get static instances. If we want to get the object's instance obj parameter, it can't be null. Otherwise, NullException will be returned.

Summary

The Field class provided by Java's reflection API encapsulates all the information of the Field:

  • The method to obtain Field instance through Class instance: getField(String name), getFields(), getDeclaredField(), getDeclaredFields()
  • The method to get the Field information through the Field instance: getName(), getType(), getModifiers()
  • Through the Field instance, you can read or set the fields of an object. If there are access restrictions, first call setAccessible(true), and then access non public fields.

Method

Get Method

Obtain the information of all methods through the Class instance. The Class class provides the following methods to obtain methods:

  • Method getmethod (string name, class <? >
  • Method[] getMethods(): get methods of all public
  • Method getdeclaredmethod (string name, class <? >... Parametertypes): get a method of the current class according to the method name and parameters
  • Method[] getDeclaredMethods(): get all methods of the current class

Take a look at the sample code:

public class MethodTest1 {
    public static void main(String[] args) throws Exception{
        Class c = Student.class;
        // Get the public method getScore, with the parameter String;
        System.out.println(c.getMethod("getScore",String.class));
        // Get the inherited public method getName, no parameters;
        System.out.println(c.getMethod("getName"));
        // Get the private method getGrade with the parameter int;
        System.out.println(c.getDeclaredMethod("getGrade",int.class));
    }
}

Operation result:

public int com.javastudy.reflection.Methods.Student.getScore(java.lang.String)
public java.lang.String com.javastudy.reflection.Methods.Person.getName()
private int com.javastudy.reflection.Methods.Student.getGrade(int)

Get Method information

A Method object contains all the information of a Method:

  • getName(): returns the method name, for example: "getScore"
  • getReturnType(): the return value type of the return method, which is a class instance, for example: "String.class"
  • getParameterTypes(): returns the parameter type of the method, which is a class array, for example: {String.class, int.class}
  • getModifiers(): return method modifier, similar to getModifiers() of Field

An example is as follows:

public class MethodTest2 {
    public static void main(String[] args) throws Exception{
        Class c = Student.class;
        Method method= c.getDeclaredMethod("getGrade",int.class);

        System.out.println("name : " + method.getName());
        System.out.println("returnType : " + method.getReturnType());
        Class<?>[] parameterTypes = method.getParameterTypes();
        System.out.println("paramaterTypes Length : " + parameterTypes.length);
        for (Class parameterType : parameterTypes){
            System.out.println("paramaterTypes : " + parameterType);
        }
    }
}

Operation result:

name : getGrade
returnType : int
paramaterTypes Length : 1
paramaterTypes : int

Calling method

Call normal method

Let's look at an example:

public class MethodTest3 {
    public static void main(String[] args) throws Exception {
        String s = "Not a bald little Li programmer";
        Method method = String.class.getMethod("substring", int.class);
        Method method2 = String.class.getMethod("substring", int.class, int.class);
        String result = (String) method.invoke(s,7);
        String result2 = (String) method2.invoke(s,1,9);
        System.out.println(result);
        System.out.println(result2);
    }
}

//Operation result:
//Programmer
//It's the bald little Li program

Analyze how Xiao Li, a programmer, is bald:

  1. Get the Method through the getMethod Method of the Class instance. The name and parameters of the getMethod are different, and the Method obtained is also different.
  2. Using the invoke Method of Method is equivalent to calling the Method. The first parameter of invoke is the object instance, and the later variable parameters are consistent with the Method parameters, otherwise an error will be reported.
Call static method

When calling a static method, you do not need to specify an instance object. The first parameter passed in by the invoke method is always null or null. Let's see the following example:

public class MethodTest4 {
    public static void main(String[] args) throws Exception{
        // Get the Integer.parseInt(Stirng) method with the parameter String
        Method method = Integer.class.getMethod("parseInt", String.class);
        // Call static method to get result
        // Integer result = (Integer)method.invoke("", "12345");
        Integer result = (Integer)method.invoke(null, "12345");
        System.out.println(result);
    }
}

//Operation result: 12345
Call a non public method

For non public methods, we can get them through Class.getDeclaredMethod(), but an IllegalAccessException will be thrown when calling. In order to call a non public method, the Method.setAccessible(true) allows it to call:

public class MethodTest5 {
    public static void main(String[] args) throws Exception{
        Person p = new Person();
        Method method = p.getClass().getDeclaredMethod("setName", String.class);
        method.setAccessible(true);
        method.invoke(p,"Not a bald little Li programmer");
        System.out.println(p.name);
    }
}

In addition, setAccessible(true) may fail. If there is a SecurityManager in the runtime of the JVM, it will check according to the rules and may block setAccessible(true). For example, a SecurityManager may not allow setAccessible(true) calls to classes of java and javax start package s, which can ensure the security of the JVM core library.

polymorphic

If a Person defines the hello() Method, and its subclass Student also overrides the Method, which Method will be called when the Method obtained from Person.class acts on the Student instance?

public class MethodTest6 {
    public static void main(String[] args) throws Exception{
        // Get Person's hello method
        Method method = Person.class.getMethod("hello");
        // Call hello method on Student instance
        method.invoke(new Student());
    }
}

public class Person {
    public void hello(){
        System.out.println("Person:hello");
    }
}

public class Student extends Person {
    public void hello(){
        System.out.println("Student:hello");
    }
}

Operation result

Student:hello

It is found that Student:hello is printed out, so when using reflection to call methods, the polymorphism principle is still followed: that is, the actual type of override method is always called.

The above reflection Code:

Method m = Person.class.getMethod("hello");
m.invoke(new Student());

Amount to:

Person p = new Student();
p.hello();

Summary

The Method object provided by Java's reflection API encapsulates all the information of the Method:

  • The Method to get Method instance through Class instance: getMethod(), getMethods(), getDeclaredMethod(), getDeclaredMethods()
  • The Method to obtain the field information through the Method instance: getName(), getReturnType(), getParameterTypes(), getModifiers()
  • The Method instance can call the Method of an object: Object invoke(Object instance, Object... parameters)
  • Access non public methods by setting setAccessible(true)
  • When calling a method through reflection, you can still follow the principle of polymorphism

Constructor

Get Constructor

Obtain the information of all constructors through the Class instance. The Class class provides the following methods to obtain methods:

  • Constructor < T > getconstructor (class <? >... Parametertypes): get the constructor of public according to the parameter
  • Constructor <? > [] getconstructors(): get all public constructors
  • Constructor < T > getdeclaredconstructor (class <? >... Parametertypes): get the constructor of the current class according to the parameter
  • Constructor <? > [] getdeclaredconstructors(): get the constructors of all current classes

Constructor is always the construction method of the current class definition, which has nothing to do with the parent class, so there is no polymorphism problem.

An example is as follows:

public class ContructorTest1 {
    public static void main(String[] args) throws Exception{
        Class c = Person.class;
        Person p = (Person) c.newInstance();

        Constructor cons1 = c.getConstructor(int.class);
        Person p1 = (Person)cons1.newInstance(30);

        Constructor cons2 = c.getDeclaredConstructor(String.class);
        cons2.setAccessible(true);
        Person p2 = (Person)cons2.newInstance("Not a bald little Li programmer");

        Constructor cons3 = c.getConstructor(String.class, int.class);
        Person p3 = (Person)cons3.newInstance("Not a bald little Li programmer-35",35);
    }
}
Person.class

public class Person {
    private String name;
    private int age;

    public Person() {
        System.out.println("Person");
    }

    public Person(int age) {
        this.age = age;
        System.out.println("Person age:" + age);
    }

    private Person(String name) {
        this.name = name;
        System.out.println("Person name:" + name);
    }

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
        System.out.println("Person toString:" + toString());
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

Operation result:

Person
Person age:30
Person name:Not a bald little Li programmer
Person toString:Person{name='Not a bald little Li programmer-35', age=35}

Summary

Based on the above results, the following conclusions are drawn:

  1. The parameterless constructor is obtained through the newInstance() of the Class instance
  2. To get the parameter Constructor, you need to get the Constructor instance through the Class instance. The methods are: getConstructor(), getConstructors(), getdeclaredconstructor (Class <? >... Parametertypes), getDeclaredConstructors()
  3. Create an instance object through the Constructor's newInstance(Object... parameters)
  4. To call a non public constructor, you need to set setAccessible(true) to allow access, but it may fail.

Interface

We can get all interfaces implemented by the current Class through getInterfaces(), as shown in the following example:

public class ReflectionInterfaceTest {
    public static void main(String[] args) {
        Class s = Integer.class;
        Class[] interfaces = s.getInterfaces();
        for (Class c:interfaces){
            System.out.println(c);
        }
    }
}

Operation result:

interface java.lang.Comparable

summary

Now that you have a general understanding of reflexes, let's review:

  • Reflection is one of the features of Java, which can dynamically get objects through reflection.
  • The purpose of reflection: design patterns such as proxy pattern; database connection through JDBC; dynamic loading of objects by Spring framework
  • Advantages of reflection: dynamic loading and improved code flexibility
  • Disadvantages of reflection: performance problems, safety restrictions, internal leakage
  • Use of reflection: by getting the Class instance, we can get all the information we want, including getting member variables, methods and constructors, which correspond to fields, methods and constructors respectively. Information can be obtained through the internal methods of these classes, for example: getName().
  • If we modify or access variables or methods with private, we need to set method.setAccessible(true) before we can carry out subsequent operations.

In the next section, I'll show you the principle of reflection and let us know more about it.

Reference resources

https://blog.csdn.net/carson_...

https://zhidao.baidu.com/ques...

https://www.liaoxuefeng.com/w...

Keywords: Java jvm Database JDBC

Added by johnsonzhang on Thu, 12 Dec 2019 15:07:59 +0200