Thank you for joining me in the Android world to fight monsters and upgrade!

Reflection is rarely used in normal development, but is frequently used in various frameworks (e.g., older versions of ButterKnife use annotations and reflection initializer controllers and omit findViewById), and this knowledge is essential if you are interested in becoming an architect.

What is reflection

In normal development, objects are created through the new keyword. Through the instance of the object, we can obtain the accessible member variable of the object or call the callable method. At this time, we know exactly what class is used.

If we don’t know what class to initialize, we need to use the reflection API that JAVA provides for us.

1.1 define

Reflection can be performed at runtime:

  • Construct an object of any class
  • Know the class to which any object belongs
  • Know the member variables and methods of any class
  • Calls properties and methods of any object

The function of dynamically retrieving program information and calling objects is called reflection mechanism. Reflection is the key to JAVA being seen as a dynamic language.

1.2 the principle

The class is retrieved at run time, but at run time the.java file is already compiled into the.class file at compile time, so the principle of reflection is that the runtime obtains all the information about the class from the bytecode file.

1.3 the advantages and disadvantages

Advantages:

  • High degree of freedom: it can ignore access restrictions and still be called by private modification.

Disadvantages:

  • Poor performance: Reflection is particularly time consuming and slower than direct object creation, so use it to weigh whether the benefits outweigh the performance impact.
  • Poor safety: The high degree of freedom of reflection directly leads to the destruction of class encapsulation.
    • When modifying code through reflection, because you are directly manipulating bytecode files, if you are not familiar with the code, it is extremely easy to cause errors due to modification.
    • Sometimes method names are used directly in reflection, and errors can be reported if method name changes are made during later maintenance.

Second, the use of reflection

The Class Class has a lot of methods, so we’ll just write a few common examples. Just remember that reflection can get all the member variables and methods in a Class (regardless of permissions) you want.

2.1 Fetching classes at runtime

As can be seen from the principle of reflection in section 1.2, the use of reflection requires the first class to be obtained at runtime. There are four methods to obtain a class at runtime, depending on the situation:

The runtime gets it directly from the class

Class<Fruit> fruitClass1 = Fruit.class;
Copy the code

The runtime retrieves the corresponding class from the object

Fruit fruit = new Fruit();
Class fruitClass2 = fruit.getClass();
Copy the code

The static method of the Class is obtained at runtime

Class fruitClass3 = Class.forName("com.kproduce.androidstudy.test.Fruit");
Copy the code

4. Get it from the class loader

Class fruitClass4 = getClassLoader().loadClass("com.kproduce.androidstudy.test.Fruit");
Copy the code

The resulting Class is the same in all four ways.

// The following results are true
System.out.println(fruitClass1 == fruitClass2);
System.out.println(fruitClass2 == fruitClass3);
System.out.println(fruitClass3 == fruitClass4);
Copy the code

2.2 Creating objects at runtime

Objects are created from the Class Class obtained in 2.1.

// The Class obtained in 2.1
Class<Fruit> fruitClass = Fruit.class;

// Call a method in the Class Class to create an object
Fruit fruit = fruitClass.newInstance();
Copy the code

2.3 Get the constructor

The constructors of a class can be many depending on the parameters, so there are apis that can get all of them directly or a constructor depending on the parameters.

// Class with four constructors
public class Fruit {

    public String name;
    private int type;
    
    public Fruit(a) {}public Fruit(String name) {
        this.name = name;
    }

    public Fruit(int type) {
        this.type = type;
    }

    public Fruit(String name, int type) {
        this.name = name;
        this.type = type; }}Copy the code

1, Get all constructors: getConstructors()

Constructor<Fruit>[] constructors = (Constructor<Fruit>[]) fruitClass.getConstructors();
Copy the code

2. Get a single constructor from the argument: getConstructor(parameter class…)

// Get Class at runtime
Class fruitClass = Class.forName("com.kproduce.androidstudy.test.Fruit");

// 1, struct method: Fruit()
fruitClass.getConstructor();

// 2, Fruit(String)
fruitClass.getConstructor(String.class);

// 3, struct: Fruit(int)
fruitClass.getConstructor(int.class);

// 4, Fruit(String, int)
fruitClass.getConstructor(String.class, int.class);
Copy the code

3. Create objects using constructors

// Fruit(String, int)
Constructor<Fruit> constructor = fruitClass.getConstructor(String.class, int.class);

Fruit(String, int) constructor to create an object
Fruit apple = constructor.newInstance(The word "apple".1);
Copy the code

2.4 Get all methods of a class

Similar to getting constructors, there are apis for getting all methods and a single method, but there are two sets to choose from, noting the method limitations of annotations.

1. Obtain all methods:

  • getMethods()
  • getDeclaredMethods()
// Get all methods, including those inherited from the parent class, excluding private:
Method[] methods = fruitClass.getMethods();

// Get all methods, excluding those inherited from the parent class, including private:
Method[] declaredMethods = fruitClass.getDeclaredMethods();
Copy the code

2. Obtain a single method according to parameters:

  • GetMethod (” method name “, parameter class…)
  • GetDeclaredMethod (” method name “, parameter class…)
// Get single method, including inherited from parent class, excluding private, can add arguments (parameter overloading)
fruitClass.getMethod("Method name"), the parameter class... ;// Get a single method, not inherited from the parent class, including private, can add parameters (parameter overload)
fruitClass.getDeclaredMethod("Method name"), the parameter class... ;Copy the code

3. Use method

// Get method
Method method = fruitClass.getDeclaredMethod("Method name"), the parameter class... ;// If the method is private, add the following sentence
method.setAccessible(true);

// Call a method, the argument is the object to be called, method calls need to be based on the object
method.invoke(constructor.newInstance(The word "apple".1));
Copy the code

2.5 Obtaining a class member variable

Basically the same as the get method, there are also two sets, you can assign values to variables and values, both object based. Get all member variables:

  • getMethods()
  • getDeclaredMethods()
// Get all variables, including those inherited from the parent class, excluding private:
Field[] fields = fruitClass.getFields();

// Get all variables, excluding those inherited from the parent class, including private:
Field[] declaredFields = fruitClass.getDeclaredFields();
   
Copy the code

Get a single member variable by name:

  • getField(@NonNull String name)
  • getDeclaredField(@NonNull String var1)
// Get a single member variable, including those inherited from the parent class, excluding private
Field nameFiled = fruitClass.getField("name");

// Get a single member variable, excluding those inherited from the parent class, including private
Field typeFiled = fruitClass.getDeclaredField("type");
Copy the code

3. Assign and get values to member variables

// Fetching and assigning values are object-based, so create the object first
Fruit apple = constructor.newInstance(The word "apple".1);

// Get the member variable of name
Field nameFiled = fruitClass.getField("name");

// If the variable is private, you need to add the following sentence before the operation
nameFiled.setAccessible(true);

// [value] Get the value of name, the value is "apple"
Object filed = nameFiled.get(apple);

// set name to "banana"
nameFiled.set(apple, "Banana");

Copy the code

conclusion

Finally, let’s summarize the knowledge point of reflection:

  1. Reflection can construct the object of any class, know the class of any object, know the member variables and methods of any class, and call the properties and methods of any object while the program is running.
  2. Reflection works like this: the runtime gets all the information about a class from a bytecode file.
  3. The advantage of reflection is that it has a high degree of freedom and can ignore access restrictions. The disadvantages are poor performance and security (breaking the encapsulation of the class).
  4. Reflection needs to get the class at run time, and there are four ways to get the class and learn about its methods and member variables.
  5. The calls to methods and the values and assignments of member variables in reflection operate on the basis of objects.

That concludes our introduction to reflection, and hopefully you’ll have a better understanding of reflection after reading this article. If my article can bring you a little bit of welfare, I will be happy enough.

See you next time!

The public,

Below is my wechat public account [Lao Kuang Dialect Android], all series of articles will be updated synchronously in the public account, welcome to follow.