1.反射的描述
java的反射机制是在运行状态中,对于任意类,都能知道这个类的所有方法和属性,对于任意对象的都能调用他们的方法和属性。这种动态调用的机制被称为反射。
要想解析一个类,必须得到这个类的字节码文件对象,而要解析的就是Class类。所有得获取每个类的字节码的Class类型的对象。
java对象加载的过程。new对象的时候,jvm从字节码文件中找到这个对象的class文件加载到内存中,形成对象空间和创建Class对象,再new相同的对象,不能再加载,java反射的本质就是获取Class对象反向获取对象的所有信息。
下图解释class对象的加载过程。
Class 类的实例表示正在运行的 Java 应用程序中的类和接口。也就是jvm中有N多的实例每个类都有该Class对象。(包括基本数据类型)
Class 没有公共构造方法。Class 对象是在加载类时由 Java 虚拟机以及通过调用类加载器中的defineClass方法自动构造的。也就是这不需要我们自己去处理创建,JVM已经帮我们创建好了。
知道我们主要通过获取Class类对象来反向获取类对象的所有信息。
2.获取Class的3种方式:
new Person().getClass();
Person.class;
Class.forName("com.Person");
3.对象的描述
类的构成:构造方法,属性,方法。
Class对象描述这三个用Constructor Field,Method 类描述。
Constructor查看下面的例子:
package com.JavaTest3;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
public class Demo {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
Class<Student> studentClass = Student.class;
Student student = new Student();
Class<? extends Student> aClass = student.getClass();
Class<?> aClass1 = Class.forName("com.JavaTest3.Student");
System.out.println(studentClass == aClass1); //true
System.out.println(studentClass == aClass); // true
System.out.println(aClass1 == aClass); // true
Constructor<?>[] constructors = aClass1.getConstructors(); // 获取所以的public方法
Constructor<?>[] declaredConstructors = aClass.getDeclaredConstructors();// 获取所以的方法,私有的,受保护的
for (Constructor c : constructors) {
System.out.println(c);
}
for(Constructor c1 : declaredConstructors) {
System.out.println(c1);
}
// 获取类的无参构造方法执行。
Constructor<?> constructor = aClass1.getConstructor(null);
Object o = constructor.newInstance();
// 获取类的有参方法执行
Constructor<?> constructor1 = aClass1.getConstructor(char.class);
constructor.setAccessible(true);
Object o1 = constructor1.newInstance('男');
}
}
Field类查看下面的例子:
package com.JavaTest3;
import java.lang.reflect.Field;
public class Demo1 {
public static void main(String[] args) {
try {
Class<?> aClass = Class.forName("com.JavaTest3.Student1");
Field[] fields = aClass.getFields();
for (Field f : fields){
System.out.println(f);
}
for(Field f:aClass.getDeclaredFields()){
System.out.println(f);
}
Field f = aClass.getDeclaredField("name");
Object o = aClass.getDeclaredConstructor(null).newInstance();
f.setAccessible(true); // 暴力访问
f.set(o,"周星驰");
Student1 student = (Student1)o;
System.out.println(student.getName());
}catch (Exception ex){
ex.printStackTrace();
}
}
}
Method类查看下面的例子:
package com.JavaTest3;
import java.lang.reflect.Method;
public class Demo2 {
public static void main(String[] args) {
try {
Class<?> aClass = Class.forName("com.JavaTest3.Student2");
for(Method m:aClass.getMethods()){
System.out.println(m);
}
for(Method m:aClass.getDeclaredMethods()) {
System.out.println(m);
}
Object o = aClass.getConstructor().newInstance();
Method show1 = aClass.getDeclaredMethod("show1", String.class);
show1.invoke(o, "周小青");
Method show2 = aClass.getDeclaredMethod("show2", null);
show2.invoke(o);
Method show3 = aClass.getDeclaredMethod("show3", null);
show3.invoke(o);
Method show4 = aClass.getDeclaredMethod("show4", int.class); // 私有的
show4.setAccessible(true);
show4.invoke(o,123);
}catch (Exception ex) {
ex.printStackTrace();
}
}
}
总结: 构造方法获取一般使用getDeclaredConstructors,属性一般使用getDeclaredFields 方法使用aClass.getDeclaredMethods 访问私有方法设置Accessible为true.