文章目录
- 一、反射(reflection)
- 1.概念
- 优点:
- 缺点
- 2.反射的相关类
- 1.Class类
- 1.**反射机制的起源**
- 2.获得类相关的方法
- 3.获得类中属性的相关方法
- 4.获得类中注解相关的方法
- 5.获得类中构造器相关的方法
- 6.获得类中方法相关的方法
- 2.获取Class对象的三种方法:
- 1.使用 Class.forName("类的全路径名");
- 2.使用 .class 方法。
- 3.使用类对象的 getClass() 方法
一、反射(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");//获取Class对象Student student = (Student) classStudent.newInstance();//强转,向下转向System.out.println(student);//Student{name='小明', age=20}} 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);//Student{name='王大锤', age=20}} 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");//获取Class对象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");//获取Class对象Constructor<?> constructor = classStudent.getDeclaredConstructor(String.class, int.class);//获得该类中与参数类型匹配的构造方法constructor.setAccessible(true);Student student = (Student) constructor.newInstance("小红", 18);//这里是 constructor的newInstance()方法System.out.println(student);//Student{name='小红', age=18}} 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);//trueSystem.out.println(C1 == C3);//true
- Class对象只存在一个
点击移步博客主页,欢迎光临~