Catalog
- JavaSE-反射机制-基础概述
- 1. 应用场景
- 2. 优点
- 3. 缺点
- 4. Class类解析
- 5. 获取Class类实例的方式
- 6. 反射机制是什么
- 7. 反射机制原理图(老韩)
- 8. 具体应用
JavaSE-反射机制-基础概述
1. 应用场景
常见的如下:
-
当获取到一个未知类型但是知道其中的方法名和方法参数的类对象时,可以通过反射机制调用这个方法,甚至于获取到这个类的具体信息。
-
通过配置文件动态加载类,动态调用类中的方法和属性。
2. 优点
- 动态加载:即使用到某个类时,才对这个类进行加载。
3. 缺点
- 使用反射的程序是基于解释执行的,影响程序执行速度。
4. Class类解析
了解反射机制,必须先了解Class类,Class实例是在类加载阶段完成的,即根据字节码文件,通过类加载器来实现Class类实例的加载(将字节码的二进制数据和Class类对象放入内存中)。
关于Class类,该类和普通类的主要区别在于
- 该类是由系统创建。
- 每一个普通的类都有一个对应的Class类实例,这个实例包括了普通类的字段、方法、构造函数。
Class类中常用的API
方法 | 描述 |
---|---|
getName() | 获取类的完整名称。 |
getSimpleName() | 获取类的简单名称,即去掉包名的类名。 |
getModifiers() | 获取类的修饰符,比如public 、private 等。 |
getFields() | 获取类的公共字段,包括超类的。 |
getDeclaredFields() | 获取类声明的所有字段,包括私有的。 |
getMethods() | 获取类的公共方法,包括超类的。 |
getDeclaredMethods() | 获取类声明的所有方法,包括私有的。 |
newInstance() | 创建类的一个新实例(已过时,不推荐使用)。 |
getConstructor(Class<?>... parameterTypes) | 获取指定参数类型的构造函数。 |
getDeclaredConstructor(Class<?>... parameterTypes) | 获取类声明的构造函数。 |
5. 获取Class类实例的方式
- 类名.class:通常用于传参。
- Class.forname(类的全路径名):在已知类的全路径名的前提下,多用于配置文件,读取类的全路径,加载类。
- 实例.getClass():通过对象直接获取Class类的实例。
- 对象.getClass().getClassLoader().loadClass(类的全路径名):通过类加载器获取Class类实例。
/**
* 获取Class实例的六种方式
*/
@Test
public void testGetClass() throws Exception{
//编译期间--->通过调用静态方法forName()获取
Class<?> cls = Class.forName(PATH_DOG);
System.out.println(cls);
//类加载阶段--->通过类名.class获取
cls = Dog.class;
System.out.println(cls);
//运行阶段--->通过对象实例创建Class对象
Object dog = cls.newInstance();
System.out.println(dog.toString());
Class<?> aClass = dog.getClass();
System.out.println("运行阶段:" + aClass);
//使用类加载器加载Class类的对象
Class loadClass = dog.getClass().getClassLoader().loadClass("com.aimin.Dog");
//基本数据类型
Class<Integer> integerClass = int.class;
Class<Character> characterClass = char.class;
System.out.println(integerClass);
System.out.println(characterClass);
Class<Integer> integerClass1 = Integer.TYPE;
Class<String> stringClass = String.class;
Class<Character> characterClass1 = Character.TYPE;
System.out.println(integerClass1);
System.out.println(stringClass);
System.out.println(characterClass1);
}
6. 反射机制是什么
在类加载阶段结束之后,内存中会出现所加载类对应的Class类对象,这个Class类对象包含了所加载类的全部信息,就像一面镜子一样反射了所加载类的全部信息,通过Class类对象就可以操作所加载的全部属性和方法。
7. 反射机制原理图(老韩)
这个图是韩老师课程里面画的图,对类的加载描述地很清晰
8. 具体应用
-
操作类的方法:
/** * 通过反射获取方法对象,并对方法对象进行操作 */ public class GetMethodTest { @Test public void getMethod() throws Exception{ //获取Class类Boss实例 Class bossCls = Class.forName("com.aimin.Boss"); //获取对象实例 Object o = bossCls.newInstance(); //获取公有方法对象 Method hi = bossCls.getMethod("hi", String.class); //赋值 hi.invoke(o, "aimin"); //获取私有方法对象 Method say = bossCls.getDeclaredMethod("say", int.class, String.class, char.class); //开启暴破 say.setAccessible(true); //赋值并执行方法获取返回值 //Object result = say.invoke(o, 1, "What's matter with you ?", 'a'); //由于"say"方法也是静态方法,所以也可以不指定对象 Object result = say.invoke(null, 1, "What's matter with you ?", 'a'); System.out.println((String) result); } } class Monster { } class Boss {//类 public int age; private static String name; public Boss() {//构造器 } public Monster m1() { return new Monster(); } private static String say(int n, String s, char c) {//静态方法 return n + " " + s + " " + c; } public void hi(String s) {//普通 public 方法 System.out.println("hi " + s); } }
-
操作类的属性:
/** * 通过反射操作对象(一般类型为Object)的属性 */ public class OperationFieldTest { @Test public void operationField() throws Exception{ //获取Class类对象 Class stuCls = Class.forName("com.aimin.Student"); //获取类实例 Object stu = stuCls.newInstance(); //通过属性名获取属性对象---公共字段 Field age = stuCls.getField("age"); //赋值 age.set(stu, 22); System.out.println(age.get(stu)); //通过属性名获取属性对象---私有静态字段 //由于静态字段与类加载有关,即静态对象是所有类实例共用的,所以在赋值的时候可以不指定对象实例 Field name = stuCls.getDeclaredField("name"); //开启暴破 name.setAccessible(true); //赋值 //name.set(null, "aimin"); name.set(stu, "WangBB"); System.out.println(name.get(null)); } } class Student {//类 public int age; private static String name; public Student() {//构造器 } public String toString() { return "Student [age=" + age + ", name=" + name + "]"; } }
-
获取类实例
/** * 通过反射获取类实例 */ public class NewInstanceTest { @Test public void getInstanceByClass() throws Exception{ //获取User类Class类对象 Class userCls = Class.forName("com.aimin.User"); //通过公有无参构造器创建对象 Object user01 = userCls.newInstance(); System.out.println("公有无参构造器" + user01); //通过公有有参构造器创建对象 Constructor constructor = userCls.getConstructor(String.class); Object aimin = constructor.newInstance("aimin"); System.out.println("公有有参构造器" + aimin); //通过私有构造器创建对象 //1. 获取到私有构造器 Constructor declaredConstructor = userCls.getDeclaredConstructor(int.class, String.class); //2. 开启暴破,类四暴力破解,之后才能获取到私有构造器 declaredConstructor.setAccessible(true); Object test = declaredConstructor.newInstance(1, "test"); System.out.println(test); } } class User { //User 类 private int age = 10; private String name = "韩顺平教育"; public User() {//无参 public } public User(String name) {//public 的有参构造器 this.name = name; } private User(int age, String name) {//private 有参构造器 this.age = age; this.name = name; } public String toString() { return "User [age=" + age + ", name=" + name + "]"; } }