反射学习总结 --为理解SpringMVC底层做准备
反射是什么?
通俗理解 - 照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
先看下类和字节码对象的关系
关于构造方法:
方式一:用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"); }