一、反射(reflection)
1.概念
- Java的反射机制是 在运行状态中,可以知道任何一个类的所有属性和方法
- 可以调用任意一个对象的任意方法和属性
- 拿到之后就可以进行修改
- 反射就是动态获取信息、动态调用对象方法的一种功能
优点:
- 可以获得一个类的所有属性和方法,进行调用、修改。反射运用在很多主流框架
- 提高灵活性和扩展性,降低耦合
缺点
2.反射的相关类
类名 | 用途 |
---|
Class类 | 代表类的实体,在运行的Java程序中表示类的接口 |
Field类 | 代表类的成员变量、类的属性 |
Method类 | 代表类的方法 |
Constructor类 | 代表类的构造方法 |
1.Class类
1.反射机制的起源
- Java文件被编译后会生成.class文件
- .class文件会被JVM解析成一个对象:java.long.Class
- 在运行时,每个java文件最终会变成Class类对象的一个实例
- 通过反射,获取、添加、修改这个类的属性和方法,成为一个动态的类
2.获得类相关的方法
方法 | 用途 |
---|
getClassLoader() | 获得类的加载器 |
getDeclaredClasses() | 返回一个数组,数组中包含该类中所有类和接口类的对象(包括私有的) |
forName(String className) | 根据类名返回类的对象 |
newInstance() | 创建类的实例 |
getName() | 获得类的完整路径名字 |
- 获取Class对象,通过newInstans方法创建类的实例
public static void reflectNewInstance() {
Class<?> classStudent = null;
try {
classStudent = Class.forName("reflect.Student");
Student student = (Student) classStudent.newInstance();
System.out.println(student);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
- newInstans方法会抛出 InstantiationException, IllegalAccessException两个异常
- 方法的返回值是T,被擦除成了Object,所以要进行强制类型转换
3.获得类中属性的相关方法
(以下方法返回值为Field相关)
方法 | 用途 |
---|
getField(String name) | 获得某个公有的属性对象 |
getFields() | 获得所有公有的属性对象 |
getDeclaredField(String name) | 获得某个属性对象 |
getDeclaredFields() | 获得所有属性对象 |
public static void reflectPrivateField() {
Class<?> classStudent = null;
try {
classStudent = Class.forName("reflect.Student");
Field field = classStudent.getDeclaredField("name");
field.setAccessible(true);
Student student = (Student) classStudent.newInstance();
field.set(student,"王大锤");
System.out.println(student);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
throw new RuntimeException(e);
} catch (InstantiationException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
4.获得类中注解相关的方法
方法 | 用途 |
---|
getAnnotation(Class annotationClass) | 返回该类中与参数类型匹配的公有注解对象 |
getAnnotations() | 返回该类所有的公有注解对象 |
getDeclaredAnnotation(Class annotationClass) | 返回该类中与参数类型匹配的所有注解对象 |
getDeclaredAnnotations() | 返回该类所有的注解对象 |
5.获得类中构造器相关的方法
(以下方法返回值为Constructor相关)
方法 | 用途 |
---|
getConstructor(Class…<?> parameterTypes) | 获得该类中与参数类型匹配的公有构造方法 |
getConstructors() | 获得该类的所有公有构造方法 |
getDeclaredConstructor(Class…<?> parameterTypes) | 获得该类中与参数类型匹配的构造方法 |
getDeclaredConstructors() | 获得该类所有构造方法 |
- 同理,获得该类中与参数类型匹配的构造方法
- 要传入对应构造方法中,参数类型的class对象
classStudent = Class.forName("reflect.Student");
Constructor<?> constructor = classStudent.getDeclaredConstructor(String.class, int.class);
- 这里是 constructor的newInstance()方法,传入初始化的参数列表
- 添加对应的异常,并且进行强转
- 因为是私有的构造方法,所以要调用setAccessible(true)方法,填上true 体现安全性(需要确认)
- 反射打破了封装机制
public static void reflectPrivateConstructor() {
Class<?> classStudent = null;
try {
classStudent = Class.forName("reflect.Student");
Constructor<?> constructor = classStudent.getDeclaredConstructor(String.class, int.class);
constructor.setAccessible(true);
Student student = (Student) constructor.newInstance("小红", 18);
System.out.println(student);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
} catch (InvocationTargetException e) {
} catch (InstantiationException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
}
6.获得类中方法相关的方法
(以下方法返回值为Method相关)
方法 | 用途 |
---|
getMethod(String name, Class…<?> parameterTypes) | 获得该类某个公有的方法 |
getMethods() | 获得该类所有公有的方法 |
getDeclaredMethod(String name, Class…<?> parameterTypes) | 获得该类某个方法 |
getDeclaredMethods() | 获得该类所有方法 |
public static void reflectPrivateMethod() {
Class<?> classStudent = null;
try {
classStudent = Class.forName("reflect.Student");
Method method = classStudent.getDeclaredMethod("function", String.class);
method.setAccessible(true);
Student student = (Student) classStudent.newInstance();
method.invoke(student,"不要吃");
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
} catch (InstantiationException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (InvocationTargetException e) {
throw new RuntimeException(e);
}
}
2.获取Class对象的三种方法:
1.使用 Class.forName(“类的全路径名”);
静态方法,前提是知道类的全路径名。
Class<?> C1 = null;
try {
C1 = Class.forName("reflect.Student");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
- forName会抛出 ClassNotFoundException异常, ClassNotFoundException继承于Exception
- 所以默认是一个受查异常(编译时异常),需要进行处理(JVM/手动抓取)
2.使用 .class 方法。
Class<Student> C2 = Student.class;
仅适合在编译前就已经明确要操作的 Class
3.使用类对象的 getClass() 方法
Student student = new Student();
Class<? extends Student> C3 = student.getClass();
System.out.println(C1 == C2);
System.out.println(C1 == C3);
点击移步博客主页,欢迎光临~