Java reflection actually means that in the running state, we can know the methods and properties of any class. For any object, we can call its methods and properties. We call this function of dynamically obtaining object information and calling object methods reflection mechanism.
Class Class
① Java is a class (including this interface) except for the basic type
② The data type of class/interface is Class
③ Every time a class is loaded, the JVM creates an instance of class type for it
public final class Class{ private Class(){...} //Note that it is private. Our own program cannot create a Class instance }
④ A class instance contains the complete information of a class
⑤ Getting the class information through the class instance is called reflect ion
⑥ Class instances are unique in the JVM. You can use = = as a comparison, but this comparison is accurate and different from the traceable parent class comparison of instanceof
How to get a class instance of a class
Class cls1 = String.class;//Type.class String s = "Hello"; Class cls2 = s.getclass();//getclass method (less used) Class cls3 = Class.forname("java.lang.String");//Class. Forname method {much used) boolean cls1 == cls2//ture boolean cls2 == cls3//ture
Class cls = String.class; String s = (String)cls.newInstance(); //We can use the newInstance method to create a new instance without parameters
Access field
① Field getField(name): get the field of a public (including the parent class) according to the field name
② Field getDeclaredField(name): get a field of the current class by the field name (excluding the parent class)
③ Field[] getFields(): get all public fields (including the parent class)
④ Field[] getDeclaredFields(): get all fields of the current class (excluding the parent class)
class Person { public String name; } class Student extends Person { public int score; private int grade; } public class Main { public static void main(String[] args) throws Exception { Class stdClass = Student.class; // Get the public field "score": System.out.println(stdClass.getField("score")); // Get the inherited public field "name": System.out.println(stdClass.getField("name")); // Get private field "grade": System.out.println(stdClass.getDeclaredField("grade")); } }
Get and set the value of field
Using reflection to get a Field instance of a Field is only the first step. We can also get the value of the Field corresponding to an instance.
Integer n = new Integer(123); Class cls = n.getclass(); Feild f = cls.getDeclaredFeild("value"); //get for value and set for value f.get(n);//123 these two sentences are equivalent to n.value f.set(n,456);//n becomes 456 Note that this code is actually problematic. value must be defined in private So we need to make a statement before get(): Calling Field.setAccessible(true) means that access is allowed regardless of whether the field is public or not
Calling method
①Method getMethod(name, Class… ): get the method of a public (including the parent class)
②Method getDeclaredMethod(name, Class… ): get a method of the current class (excluding the parent class)
③ Method[] getMethods(): get methods of all public (including parent class)
④ Method[] getDeclaredMethods(): get all methods of the current class (excluding the parent class)
class Person { public String getName() { return "Person"; } } class Student extends Person { public int getScore(String type) { return 100; } private int getGrade(int year) { return 1; } } public class Main { public static void main(String[] args) throws Exception { Class stdClass = Student.class; // Get the public method getScore. The parameter is String: System.out.println(stdClass.getMethod("getScore", String.class)); // Get the inherited public method getName, no parameters: System.out.println(stdClass.getMethod("getName")); // Get the private method getGrade with the parameter int: System.out.println(stdClass.getDeclaredMethod("getGrade", int.class)); } }
Invoke
public class Main { public static void main(String[] args) throws Exception { String s = "Hello world"; Method m = String.class.getMethod("substring", int.class); //Call this method on the s object String r = (String) m.invoke(s, 6); //Calling invoke on a Method instance is equivalent to calling the Method //The first parameter to invoke is the object instance //In which instance the method is called, the following variable parameters should be consistent with the method parameters, otherwise an error will be reported //For example, s here is the instance object to execute the method, and 6 is the Integer parameter in the method System.out.println(r); } } If the Method obtained represents a static Method When calling a static method, you do not need to specify an instance object So the first parameter passed in by the invoke method is always null
polymorphic
When a method is called by reflection, the same principle of polymorphism is followed: that is, the overriding method of the actual type is always called, if any.
So
Method m = Person.class.getMethod("hello"); m.invoke(new Student());
In fact, it is equivalent to:
Person p = new Student(); p.hello();
Call constructor
As mentioned earlier, we can create an instance through newInstance, but there are limitations in calling Class.newInstance(), which can only call the public parameterless constructor of the class. If the constructor has parameters or is not public, it cannot be called directly through Class.newInstance().
In order to call any constructor, the reflection API of Java provides the constructor object, which contains all the information of a constructor and can create an instance. Constructor object is very similar to Method, except that it is a constructor, and the call result always returns the instance:
public class Main { public static void main(String[] args) throws Exception { // Get the constructor Integer(int): Constructor cons1 = Integer.class.getConstructor(int.class); // Call construction method: Integer n1 = (Integer) cons1.newInstance(123); // Get the constructor Integer(String) Constructor cons2 = Integer.class.getConstructor(String.class); Integer n2 = (Integer) cons2.newInstance("456"); } }
The method of obtaining Constructor by Class instance
getConstructor(Class): gets the Constructor of a public; getDeclaredConstructor(Class): get a certain Constructor; getConstructors(): get the constructors of all public; getDeclaredConstructors(): get all constructors.
Note that Constructor is always the construction method defined by the current class, which has nothing to do with the parent class, so there is no polymorphism problem. When a non public Constructor is called, access must be allowed first through the setAccessible(true) setting.
Get inheritance relationship
Get parent class
As mentioned earlier, we can get a class instance in three different ways, so how to get the class instance of their parent class.
public class Main { public static void main(String[] args) throws Exception { Class i = Integer.class; Class n = i.getSuperclass();//Get its parent class } } //Any Class other than Object that is not interface must have a parent Class type.
Get interface
Because a Class may implement one or more interfaces, we can query the implemented interface types through Class. For example, query the interface implemented by Integer:
public class Main { public static void main(String[] args) throws Exception { Class s = Integer.class; Class[] is = s.getInterfaces(); //Traverse and print out all its interfaces for (Class i : is) { System.out.println(i); //After running, the following interfaces are available for the Sieger //java.lang.Comparable //java.lang.constant.Constable //java.lang.constant.ConstantDesc } } }
① getInterfaces() only returns the interface type directly implemented by the current class, excluding the interface type implemented by its parent class
② Calling getSuperclass() on the Class of all interfaces returns null, and getInterfaces() is used to get the parent interface of the interface
③ If a class does not implement any interface s, getInterfaces() returns an empty array.
Inheritance relationship
When we judge whether an instance is of a certain type, we normally use the instanceof operator:
Object n = new Integer(123); boolean isDouble = n instanceof Double; // false boolean isInteger = n instanceof Integer; // true boolean isNumber = n instanceof Number; // true
If there are two Class instances, you can call isAssignableFrom() to determine whether an upward transformation is valid:
Integer.class.isAssignableFrom(Integer.class); // true, because Integer can be assigned to Integer Number.class.isAssignableFrom(Integer.class); // true, because Integer can be assigned to Number Object.class.isAssignableFrom(Integer.class); // true, because Integer can be assigned to Object Integer.class.isAssignableFrom(Number.class); // false, because Number cannot be assigned to Integer
In short, judge whether the type after isAssignable From can be assigned to the former (that is, whether the latter is a subclass of the former)