preface

As we worked on Android projects using Java, we found that a number of frameworks used reflection. Reflection allows us to instantiate, call methods, and get or set variable values for any class in the run state. This ability to dynamically retrieve information and invoke object methods is called the Reflection mechanism of the Java language. Reflection is a mechanism for dynamically interacting with classes. Although Java is a static language, it can use reflection to achieve some functions only found in dynamic languages (allowing changes in program structure or variable types while programs are running).

Reflection can also be seen in the Framework layer of Android. For example, the core of AMS to start an Activity is the use of reflection mechanism, and the Activity object used is built by reflection.

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) { ... Activity activity = null; try { java.lang.ClassLoader cl = appContext.getClassLoader(); activity = mInstrumentation.newActivity( cl, component.getClassName(), r.intent); .Copy the code

Finally call instantiateActivity to create the instance via cl.loadClass(className).newinstance () reflection

public @NonNull Activity instantiateActivity(@NonNull ClassLoader cl, @NonNull String className,
            @Nullable Intent intent)
            throws InstantiationException, IllegalAccessException, ClassNotFoundException {
        return (Activity) cl.loadClass(className).newInstance();
    }
Copy the code

What can reflection do

  • Gets the class information of an object
  • Construct any class object at run time
  • Determine the class to which any object belongs at run time
  • Gets and invokes member methods and variables that any class has at run time
  • Gets and calls the member variables and methods of any object at run time
  • Gets a class’s access modifiers (public, private), members, methods, annotations, superclasses, and so on
  • Gets constants and method declarations that belong to an interface
  • Use reflection to load classes dynamically, support hot fixes and plugins
  • Hook methods are executed through dynamic proxies

The main classes related to reflection

  • Java.lang. Class: Represents a Class, and the Class object represents an object in the heap after a Class has been loaded
  • Java. Lang. Reflect. Method: on behalf of the class, the Method of object Method means that a class Method
  • Java.lang.reflect. Field: represents a member variable of a class, and a Field object represents a member variable of a class
  • Java. Lang. Reflect. Constructor: on behalf of the Constructor of a class

Get the class object

What is a Class object and how do I get it

  • Class is also a Class, which also inherits from Object

  • Class objects are not new; they are created by the system.

    The traditional way to load new Cat() is using a classLoader

    Use class.forname (), still loading by ClassLoader

@CallerSensitive public static Class<? > forName(String className) throws ClassNotFoundException { Class<? > caller = Reflection.getCallerClass(); return forName(className, true, ClassLoader.getClassLoader(caller)); }Copy the code
  • There can only be one copy of a Class object in memory because the Class is loaded only once
  • Each object instance remembers which Class instance it was generated from
  • Class is the complete structure of a Class
  • Class objects are stored on the heap
  • The bytecode binary data of a class that is placed in the method area, also known as the class’s metadata (method code, variable name, method name, access rights, etc.)

When the JVM loads a class, it generates a unique class object for each class.

  • Class.forname ()– get at compile time
  • Class name. Class —- Obtained during loading
  • Object. GetClass ()– run-time fetch
  • Classloader.loadclass ()– The classLoader gets the class object
  • Basic data type, which can be passedBasic datatype.classTo obtain
  • The wrapper class for the basic datatype. You can get the class object with.typeA wrapper class TYPE

1. If you know the full name of a class and the class is in the classpath, you can obtain the full name of the class through the static method forName of the class. It is used to read the full path of the class from the configuration file and then load the class

Class.forName(String className);
Copy the code

Class CLS = A.class. This method is mostly used for parameter passing, such as obtaining the corresponding constructor object through reflection

Class c = Person.class;
Copy the code

CLS = object.getClass (); CLS = object.getClass ()

Person p = new Person();
Class clazz = p.getClass();
Copy the code

4. Obtain the Class object of the Class through the Class loader

Which types have Class objects

  • Outer class, member inner class, static inner class, local inner class, anonymous inner class
  • Interface interface
  • data
  • Enum enumeration
  • The annotation annotations
  • Basic data types
  • void

Get the structure information of the class through reflection

What structural information is available?

  • GetName — Gets the name of the entire class
  • GetSimpleName – Gets the name of the simple class
  • GetFields — Gets all public modified properties, including this class and its parent
  • GetDeclaredFields – Gets all attributes in this class
  • GetMethods — Get all public modifier methods, including this class and its parent
  • GetDeclaredMethods – Gets all methods in this class
  • GetConstructors – Gets all public constructors for this class
  • GetDeclaredConstructors – Gets all constructors in this class
  • GetPackage – Returns package information in package form
  • GetSuperClass – Returns the parent Class information in Class form
  • GetInterfaces — returns interface information in Class[] form
  • Getanannotations – returns all annotations as annotations []

Get Field information

java.lang.reflect.Field

  • GetModifiers: Return modifiers as ints (default modifiers are 0, public is 1, private is 2, protected is 4, static is 8, and final is 16)
  • GetType: Returns the type in Class form
  • GetName: Returns the property name

Access Method

Java. Lang. Reflect the class Method

  • GetModifiers: Return modifiers as ints (default modifiers are 0,public is 1, private is 2, protected is 4, static is 8, and final is 16)
  • GetReturnType: gets the return type in Class form
  • GetName: Returns the method name
  • GetParameterTypes: Returns an array of parameter types in Class[]

Create objects through reflection

How to create

  1. Option 1: Call the public modifier no-argument constructor in the class
  • Gets the Class object of the Class
  • Call newInstance() to the obtained Class Object to return an Object of type Object, requiring a strong turn.
// Get user's Class<? > userClass = Class.forName("fanshe.User"); // Create an object with no arguments User newInstance = (User) userclass.newinstance ();Copy the code
  1. Approach 2: Invoke the specified constructor in the class
  • Gets the Class object of the Class
  • callGetConstructor ()Get a Constructor object
  • Create objects using the Constructor newInstance() method
// Get user's Class<? > userClass = Class.forName("fanshe.User"); Public Constructor<? > constructor = userClass.getConstructor(String.class); User newInstance2 = (User)constructor.newInstance("abc");Copy the code

The first method uses only the default constructor and cannot create an object through a constructor with parameters. The second way is to create an object by specifying a constructor for the parameters.

Modify the property Field by reflection

/ / get the name of the attribute value of the private Field name = userClass. GetDeclaredField (" name "); // You can change the private property value name.setaccessible (true); name.set(obj, "zhangsan"); String n = (String)name.get(obj); System.out.println(n);Copy the code

Call the Method through reflection

Method = cls.getMethod("staticMethodName", "staticMethodName", "staticMethodName"); new Class[] {double.class,String.class}); Invoke = method.invoke(null, new Object[] {1.0," ABC "}); // Invoke (null, new Object[] {1.0," ABC "}); // If the method is a private private method, the access property must be changed to NoSuchMethodException; // method.setaccessible (true); // If the method is private, the access property must be changed to NoSuchMethodException. / / private Method through the launch can modify its access / / 2. Non-static Method an = CLS. GetMethod (" methodName ", new Class [] {a double Class, String. The Class}); Object Invoke2 = method2.invoke(new Cat(), new Object[] {2.0,"abcd"}); Print Method = cls.getMethod("print", new Class[]{}); Object result_3 = method_3.invoke(new Cat(), null);Copy the code

Precautions for using launches

Performance issues

Code is optimized by the compiler at compile time, which results in better performance and less overhead. Reflection’s performance issues, especially on mobile devices, come from not being able to enjoy compiler optimizations. In addition, reflection is used to traverse the fields and methods of the class. This traversal has its own performance loss, and there is also language level unboxing and boxing during parameter passing and invocation, which is one of the reasons for performance loss.

  • Advantages: Objects can be created and used dynamically, with flexibility. Without reflection, the framework loses low-level support
  • Disadvantages: The use of reflection is basically interpreted execution, execution speed is affected
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, InstantiationException, NoSuchMethodException, SecurityException { m1(); m2(); } public static void m1() {Cat Cat = new Cat(); long start = System.currentTimeMillis(); for(int i = 0; i<900000; i++) { cat.hi(); } long end = System.currentTimeMillis(); System.out.println(" normal call "+(end-start)); } / / reflection calls public static void m2 () throws ClassNotFoundException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, InstantiationException, NoSuchMethodException, SecurityException { Class cat = Class.forName("reflect.Cat"); Object newCat = cat.newInstance(); Method method = cat.getMethod("hi"); long start = System.currentTimeMillis(); for(int i = 0; i<900000; i++) { method.invoke(newCat); } long end = System.currentTimeMillis(); System.out.println(" reflection call "+(end-start)); }Copy the code
Normal call 4 reflection call 26Copy the code

Optimization: Turn off access checking

  • Method and Field and Constructor objects both have setAccessible methods
  • Enables or disables access security check
  • If this parameter is set to true, the access check is cancelled when the reflected object is in use, improving the efficiency of reflection. A value of false indicates that the reflected object performs an access check

conclusion

Reflection is a very useful mechanism that is widely used in many frameworks. Understanding the principles and apis of reflection is a must for Java/Android programmers. Next I’ll dive into the practical uses of reflection, such as the principles and parsing of dynamic proxies.