反射是什么?

  通俗理解 - 照X光。

  java:一个类在反射面前就像照X光,清清楚楚明明白白。

  应用:我们的ide中,能够"."一下就知道类中的所有方法就是通过反射实现的。

     XML中配置的class全路径动态生成类。(框架)

  程序在运行过程中,动态的创建对象。

    -- 只要知道类的名称,就可以利用他的字节码对象来创建该类的一个对象。

何为class对象:

  HelloWorld.java

  通过 javac HelloWorld.java   ----->HelloWorld.class(字节码文件) ---> java HelloWorld    jvm把HelloWorld.class加载到内存中,变成Class对象

  

关于Class的加载:

public static void main(String[] args) {
        Person p = new Person();
        Class pClassclass = p.getClass();
        System.out.println(pClassclass);
        Person person = new Person("aa", "18", "USA");
        Class personClass  = person.getClass();
        System.out.println(personClass);
        System.out.println(pClassclass == personClass); //true 字节码文件在程序运行过程中,只会被加载到内存中一次
    }

  

获取Class的三种方法: p.getClass(),  Person.class,  Class.forName("类名全路径")

public static void main(String[] args) throws ClassNotFoundException {
        Person p = new Person();
        Class p1 = p.getClass();
        Person person = new Person("aa", "18", "USA");
        Class p2  = person.getClass();
        System.out.println(p1 == p2);
        Class<Person> p3 = Person.class;
        System.out.println(p3 == p1);
        Class<?> p4 = Class.forName("com.java.demo.clazz.Person");
        System.out.println(p4 == p3);
    }

无论是哪一种,字节码都只有一个

使用Class

  先看下类和字节码对象的关系

  反射学习总结 --为理解SpringMVC底层做准备-LMLPHP

关于构造方法:

  方式一:用newInstance()方法

  class.newInstance(),时,newInstance()底层需要调用无参的构造方法,所以,我们被反射的类中,需要有一个无参的构造方法

public static void main(String[] args) throws IllegalAccessException, InstantiationException, ClassNotFoundException {
        //通过字节码对象,创建一个对象
        Class<?> aClass = Class.forName("com.java.demo.clazz.Person");
        Person person = (Person) aClass.newInstance();

    }

  方式二:用Constructor, 这个时候,空参的构造方法就是非必须的了。

public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        Class<?> aClass = Class.forName("com.java.demo.clazz.Person");
        Constructor<?> constructor = aClass.getConstructor(String.class, String.class,String.class);
        Person instance = (Person)constructor.newInstance("aa", "18", "USA");
    }

  方式二的增强版:当用的是getDeclaredConstructor()方法,setAccessible(true)之后,就算他的构造方法是private的也能创建对象(他能获取到所有的东西,包括公共的私有的)

public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        Class<?> aClass = Class.forName("com.java.demo.clazz.Person");
        Constructor<?> constructor = aClass.getDeclaredConstructor(String.class, String.class,String.class);
        constructor.setAccessible(true); //暴力访问 IllegalAccessException
        Person instance = (Person)constructor.newInstance("aa", "18", "USA");
    }

获取Field(成员变量)

  只要是Declared的,就能获取到所有声明的变量

public static void main(String[] args) {
        Class<Person> personClass = Person.class;
        Field[] fields = personClass.getFields(); //这种只能获取到公共的
        for (Field f : fields) {
            System.out.println(f);
        }
        Field[] declaredFields = personClass.getDeclaredFields(); //这种可以获取到所有的
        for (Field f : declaredFields) {
            System.out.println(f);
        }
    }

获取Method(类中的方法)

  只要是Declared的,就能获取到所有声明的方法

public static void main(String[] args) {
        Class<Person> personClass = Person.class;
        Method[] declaredMethods = personClass.getDeclaredMethods();
        for (Method method : declaredMethods){
            System.out.println(method);
        }
    }

  Method方法的调用

public static void main(String[] args) throws IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchMethodException {
        Class<Person> personClass = Person.class;
        Person person = personClass.newInstance();
        Method spark = personClass.getDeclaredMethod("spark",String.class);
        //执行方法,invoke, 两个参数
        //第一个参数method属于那个对象,第二个对象方法参数
        spark.setAccessible(true);
        spark.invoke(person,"HeLLO GRIL");
    }
03-14 21:53