Detailed explanation of Java reflection technology with source code

When I was learning Java at school, I didn't learn it solidly and I didn't experience too many practical projects, so many important knowledge points passed at a glance. There are many places that need reflection, and I have to study again. I owe too much debt in school, and it is time to pay it off slowly.

(1) What is reflection?

The Java reflection mechanism is that in the running state, for any class, you can know all the properties and methods of this class; for any object, you can call any of its methods and properties; this dynamically obtained information and dynamic call The function of the method of the object is called the reflection mechanism of the Java language.

Simply put:
1. The object operation object is created by the new keyword, which has been determined at compile time.
2. Through reflection, objects can be dynamically manipulated during program operation, and information that cannot be obtained during compilation can be obtained. Dynamic operations maximize the extensibility of Java.

Reflection is the soul of the framework. It can effectively reduce the coupling between classes. Many frameworks use the reflection principle. For example, hibernate's entity classes, Spring's AOP, etc. all have reflection implementations.

(2) The specific realization of reflection

To implement reflection, you must first get the bytecode file object (.class) of the class. Through the bytecode file object, you can get all the information we want through the methods in this class. Each class Corresponding to a bytecode file also corresponds to an object of type Class, that is, a bytecode file object.

1. Three ways to get the bytecode file object (Class)

   /**
     * 方式一:
     * Object中的getClass方法来获取Class对象
     * 使用这方式必须有具体的类,并创建对象。
     * 这种方式使用的少,一般是传的是Object,不知道类型的时候才使用。
     */
            Object obj=new Proson();
	        Class clazz1 =obj.getClass();
	        System.err.println("通过getClass():"+clazz1);


   /**
     * 方式二:
     * 直接通过 类名.class来获取Class对象。
     * 任何类型中都具有隐含的静态成员变量class,使用简单,但是扩展性还是不足。
     */
            Class clazz2=Proson.class;
	        System.err.println("通过类名.class:"+clazz2);


  /**
     * 方式三:
     * 通过Class 对象的forName()静态方法来获取Class对象。
     * 使用最多,通过类的全限定名,但可能抛出ClassNotFoundException异常
     */
          Class clazz3 = Class.forName("com.xiaoli.bean.Proson");
	      System.err.println("通过类的全限定名:"+clazz3);

         //比较三种方法对象是否是相同实例。
	       System.err.println(clazz1==clazz2);
	       System.err.println(clazz1==clazz3);
	       System.err.println(clazz2==clazz3);

The result of the operation is known

  1. All three methods can get the bytecode file object.
  2. A class has only one instance of Class in the JVM (all true after comparison)

insert image description here

2. How the object is created.

Proson type

 public class Proson {
    
    
    //私有属性
    private String name;
    //公有属性
    public  Integer age;
    //无参构造
    public Proson() {
    
    
    }
    //有参构造
    public Proson(String name, Integer age) {
    
    
        this.name = name;
        this.age = age;
    }
    //私有方法
     private void method1(){
    
    
        System.err.println("method1——run");
    }
    //公有方法
    public void method2(String param){
    
    
        System.err.println("method1=2——run :"+param);
    }


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

The method of instantiating objects
deepens the understanding of reflection by comparing the new keyword with reflection. The detailed code is as follows:

	 // 不用反射: 创建对象,需要手动new对象不能动态创建。
	 // new的时候根据new的类名寻找字节码文件,加载进入内存,创建Class对象,并接着创建对应的Proson对象。
         Proson p=new Proson();

        //通过反射:只需要一个名字,就可以创建对象。
        String className="com.xiaoli.bean.Proson";
        //寻找该名称的类文件,加载进内存,并创建Class对象。
        Class clazz = Class.forName(className);
        //通过Class对象的newInstance()创建类对象。
        Object o = clazz.newInstance();


Call the parameterized construction method to initialize the variable
Contrast reflection through the parameterized construction. The detailed code is as follows:

        //不用反射:通过构造方法实例化并初始化变量
        Object obj1=new Proson("name",18);
        System.err.println("不用反射: "+obj1);
        //通过反射:Class对象的getConstructor方法拿到构造器。
        Constructor constructor = clazz.getConstructor(String.class, Integer.class);
        //通过构造器的newInstance方法实例化并初始化变量
        Object obj2=constructor.newInstance("name2",22);
        System.err.println("通过反射: "+obj2);

got the answer
insert image description here

(3) Detailed explanation of the methods in the Class class

At this point, you should understand the importance of Class to reflection, right? So what are the common methods in the Class class?

Get the public constructor getConstructors()
Get all the constructors getDeclaredConstructors()
Get the object of this class newInstance()
Get the class name including the package path getName()
Get the class name without the package path getSimpleName()
Get all the properties of the public type of the class getFields()
Get all properties of the class getDeclaredFields()
Get the specified properties of the public type of the class getField(String name)
Get the specified properties of all types of the class getDeclaredField(String name)
Get the methods of the public type of the class getMethods()
Get all the methods of the class getDeclaredMethods()
Get Specific public type methods of the class: getMethod(String name, Class[] parameterTypes)
get the inner class getDeclaredClasses()
get the outer class getDeclaringClass()
get the modifiers getModifiers()
get the package getPackage()
get the implemented interface getInterfaces()

Some examples are used to demonstrate the above common methods. The detailed code is as follows.

       //这里方便操作演示用第二种发方法获取字节码对象
        Class clazz2=Proson.class;
        //通过反射调用有参构造函数初始化对象(上面演示过) 
        Constructor constructor = clazz2.getConstructor(String.class, Integer.class);
        Object obj = constructor.newInstance("lixiaoli", 18);

       //获得类完整的名字
        String className1 = clazz2.getName();
        System.err.println("1类完整的名字: "+className1);

       //获得类名不包含包路径
        String className2 = clazz2.getSimpleName();
        System.err.println("2类名不含路径: "+className2);

        //获得类中公共类型(public)属性
        Field[] fields = clazz2.getFields();
        String fieldName="";
        for(Field field : fields){
    
    
            fieldName+=field.getName()+"  ";
        }
        System.err.println("3类中公共属性: "+fieldName);

        //获得类中全部类型(包括私有)属性
        Field[] fieldsAll = clazz2.getDeclaredFields();
        fieldName="";
        for(Field field : fieldsAll){
    
    
            fieldName+=field.getName()+"  ";
        }
        System.err.println("4类中全部属性: "+fieldName);

        //获得公共指定属性值
        Field age = clazz2.getField("age");
        Object o = age.get(obj);
        System.err.println("5公共指定属性: "+o);

        //获得私有指定属性值
        Field name = clazz2.getDeclaredField("name");
        // Field name = clazz2.getField("name");只能获取共有属性 故此方法会抛出NoSuchFieldException异常,所以选用getDeclaredField();
        name.setAccessible(true); //设置为true才能获取私有属性
        Object o2 = name.get(obj);
        System.err.println("6类中私有指定属性值: "+o2);

        //获取类所有公共类型方法   这里包括 Object 类的一些方法
        Method[] methods = clazz2.getMethods();
        String methodsName="";
        for(Method method : methods){
    
    
            methodsName+=method.getName()+"  ";
        }
        System.err.println("7类公共类型方法: "+methodsName);

        //获取该类中的所有方法(包括私有)
        Method[] methodsAll = clazz2.getDeclaredMethods();
        methodsName="";
        for(Method method : methodsAll){
    
    
            methodsName+=method.getName()+"  ";
        }
        System.err.println("8类中的所有方法: "+methodsName);

        //获取并使用指定方法
        Method method1 = clazz2.getDeclaredMethod("method1");//获取无参私有方法
        method1.setAccessible(true);//设置为true才能获取私有方法
        method1.invoke(obj);//调用无参方法

        Method method2 = clazz2.getMethod("method2",String.class);//获取有参数方法
        method2.invoke(obj,"666");//调用有参方法

Running Results
insert image description here
Four Reflections Summary
Skilled use of reflection can reduce the coupling degree of our program, but of course some performance will be lost.

The above is my learning and understanding of the Java reflection mechanism. If there are any mistakes, please point them out so that they can be corrected in time! Thanks!

Copyright statement : This article is an original article by the blogger and may not be reproduced without the blogger's permission https://blog.csdn.net/qq_44614710/article/details/86741226

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324103585&siteId=291194637