兴趣爱好Javajava学习笔记(二十三)- 反射
执笔 反射机制
- 反射机制(Java Refection)允许程序在执行期借助与Refection API取得任何类的内部信息(如:成员变量、构造器、成员方法等),并能直接操作对象的属性及方法
1、应用
- 在运行时判断任意一个对象所属的类
- 在运行时构造任意一个类的对象
- 在运行时得到任意一个类所具有的成员变量和方法
- 在运行时调用任意一个对象的成员变量和方法
- 生成动态代理
相关的类
1 2 3 4
| (1)java.lang.Class (2)java.lang.reflect.Method (3)java.lang.reflect.Field (4)java.lang.reflect.Constructor
|
3、优点和缺点
-
优点:
- 可以动态的创建和使用对象(框架底层核心),使用灵活
-
缺点:
调用优化
Class类
基本介绍
-
Class类也是类,继承了Object类
-
Class类对象不是new出来的,而是系统创建的
-
对于某个类的Class对象,在内存中只有一份,因为类只加载一次
-
通过Class对象可以得到一个类的完整结构
-
Class对象存放在堆中
-
类的字节码二进制数据,是放在方法区(或者称为类的元数据(包括方法代码、变量名、方法名、访问权限等)
- 反射/java程序在计算机中的三个阶段.png)
应用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| public class Class02 { public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchFieldException { String classAllPath = "com.hzy.study.Car"; Class<?> cls = Class.forName(classAllPath); System.out.println(cls); System.out.println(cls.getClass()); System.out.println(cls.getPackage().getName()); System.out.println(cls.getName()); Car car = (Car)cls.newInstance(); System.out.println(car); Field brand = cls.getField("brand"); System.out.println(brand.get(car)); brand.set(car,"奔驰"); System.out.println(brand.get(car)); Field[] fields = cls.getFields(); for (Field f : fields) { System.out.println(f.getName()); } } }
|
获取Class对象
Class.forName
- 前提:已知一个类的全类名,且该类在类的路径下,可通过Class类的静态方法forName()获取
- 应用场景:多用于配置文件,读取类全路径,加载类
1 2 3 4
| String classAllPath = "com.hzy.study.Car"; Class cls = Class.forName(classAllPath); System.out.println(cls);
|
类名.Class
- 前提:已知具体的类,通过类的Class获取,该方式最为安全可靠,程序性能最高
- 应用场景:多用于参数传递
1 2 3
| Class cls2 = Car.class; System.out.println(cls2);
|
对象.getClass()
- 前提:已知某个类的实例,调用该实例的getClass()方法获取Class对象
- 应用场景:通过创建好的对象,获取Class对象
1 2 3 4
| Car car = new Car(); Class<? extends Car> cls3 = car.getClass(); System.out.println(cls3);
|
通过类加载器[4种]
1 2 3 4 5 6 7 8 9
|
ClassLoader classLoader = car.getClass().getClassLoader();
Class<?> cls4 = classLoader.loadClass(classAllPath); System.out.println(cls4);
|
基本数据类型
1 2 3 4 5 6
|
Class<Integer> integerClass = int.class; Class<Character> characterClass = char.class; Class<Boolean> booleanClass = boolean.class; System.out.println(integerClass);
|
基本数据类型的包装类
1 2 3 4 5
|
Class<Integer> type1 = Integer.TYPE; Class<Character> type2 = Character.TYPE; System.out.println(type1);
|
拥有Class对象的类型
1 2 3 4 5 6 7 8 9 10
| Class<String> cls = String.class; Class<Serializable> cls2 = Serializable.class; Class<Integer[]> cls3 = Integer[].class; Class<float[][]> cls4 = float[][].class; Class<Deprecated> cls5 = Deprecated.class;
Class<Thread.State> cls6 = Thread.State.class; Class<Float> cls7 = float.class; Class<Void> cls8 = void.class; Class<Class> cls9 = Class.class;
|
类加载
静态加载
- 编译时加载相关的类,如果没有就报错,依赖性强
- 场景:
- 当创建对象时(new)
- 当子类被夹在时,父类也加载
- 调用类中的静态成员
动态加载
- 运行时加载需要的类,如果不运行时不用该类,即使不存在该类也不报错,降低了依赖性
- 场景:反射
类加载过程
- 反射/类加载过程.png)
加载阶段
- 将字节码从不同的数据源(class文件、jar包、网络)转化为二进制字节流加载到内存中,并生成一个代表该类的java.lang.Class对象
连接阶段
验证
- 目的是为了确保Class文件的字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身的安全
- 包括:问价格式验证(是否以魔数 oxcafebabe开头)、元数据验证、字节码验证和符号引用验证
- 缩短虚拟机类加载时间:-Xverify:none 参数来关闭大部分的类验证措施
准备
- 对静态变量分配内存并初始化(对应数据类型的默认初始值:如0、0L、null、false等),这些变量所使用的的内存都将在方法区中进行分配
解析
初始化(initialization)
- 到初始化阶段,才真正开始执行类中定义的Java程序代码,此阶段是执行(0)方法的过程
- ()方法是由编译器按语句在源文件中出现的顺序,依次自动收集类中的所有静态变量的赋值动作和静态代码块中的语句,并进行合并
- 虚拟机会保证一个类的()方法在多线程环境中被正确地加锁、同步,如果多个线程同时去初始化一个类,那么只会有一个线程去执行这个类的()方法,其他线程都需要阻塞等待,直到活动线程执行()方法完毕
反射获取类结构信息
java.lang.Class类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
| @Test public void api_01() throws ClassNotFoundException { Class<?> personCls = Class.forName("com.hzy.study.reflection.Person"); System.out.println(personCls.getName()); System.out.println(personCls.getSimpleName()); Field[] fields = personCls.getFields(); for (Field field : fields) { System.out.println("本类以及父类public 修饰的属性 " + field.getName()); } Field[] declaredFields = personCls.getDeclaredFields(); for (Field declaredField : declaredFields) { System.out.println("本类中所有的属性=" + declaredField.getName()); } Method[] methods = personCls.getMethods(); for (Method method : methods) { System.out.println("本类及父类所有public 修饰的方法=" + method.getName()); } Method[] declaredMethods = personCls.getDeclaredMethods(); for (Method declaredMethod : declaredMethods) { System.out.println("本类中所有的方法" + declaredMethod.getName()); } Constructor<?>[] constructors = personCls.getConstructors(); for (Constructor<?> constructor : constructors) { System.out.println("本类所有public 修饰的构造器" + constructor.getName()); } Constructor<?>[] declaredConstructors = personCls.getDeclaredConstructors(); for (Constructor<?> declaredConstructor : declaredConstructors) { System.out.println("本类所有的构造器=" + declaredConstructor.getName()); } System.out.println(personCls.getPackage()); Class<?> superclass = personCls.getSuperclass(); System.out.println("父类信息=" + superclass.getName()); Class<?>[] interfaces = personCls.getInterfaces(); for (Class<?> anInterface : interfaces) { System.out.println("接口信息=" + interfaces); } Annotation[] annotations = personCls.getAnnotations(); for (Annotation annotation : annotations) { System.out.println("注解信息=" + annotation); } }
|
java.lang.reflect.Field类
1 2 3 4
| getModifiers
getType getName
|
1 2 3 4 5 6 7 8 9
| Class<?> personCls = Class.forName("com.hzy.study.reflection.Person"); Field[] declaredFields = personCls.getDeclaredFields(); for (Field declaredField : declaredFields) { System.out.println("本类中所有的属性=" + declaredField.getName() + " 该属性的修饰值=" + declaredField.getModifiers() + " 该属性的类型=" + declaredField.getType()); }
|
java.lang.reflect.Method类
1 2 3 4 5
| getModifiers
getReturnType getName getParameterTypes
|
1 2 3 4 5 6 7 8 9 10 11 12
| Method[] declaredMethods = personCls.getDeclaredMethods(); for (Method declaredMethod : declaredMethods) { System.out.println("本类中所有的方法" + declaredMethod.getName() + " 该方法的访问修饰符的值=" + declaredMethod.getModifiers() + " 该方法的返回类型=" + declaredMethod.getReturnType());
Class<?>[] parameterTypes = declaredMethod.getParameterTypes(); for (Class<?> parameterType : parameterTypes) { System.out.println(" 该方法的返回参数类型=" + parameterType); } }
|
java.lang.reflect.Constructor类
1 2 3
| getModifiers getName getParameterTypes
|
1 2 3 4 5 6 7 8 9 10
| Constructor<?>[] declaredConstructors = personCls.getDeclaredConstructors(); for (Constructor<?> declaredConstructor : declaredConstructors) { System.out.println("本类所有的构造器=" + declaredConstructor.getName());
Class<?>[] parameterTypes = declaredConstructor.getParameterTypes(); for (Class<?> parameterType : parameterTypes) { System.out.println(" 该构造器的返回形参类型=" + parameterType); } }
|
反射创建对象
通过类中public修饰的无参构造器
1 2 3 4 5
| Class<?> userClass = Class.forName("com.hzy.study.reflection.User");
Object user1 = userClass.newInstance(); System.out.println(user1);
|
通过类中public修饰的有参构造器
1 2 3 4 5 6
|
Constructor<?> constructor = userClass.getConstructor(String.class);
Object user2 = constructor.newInstance("执笔"); System.out.println(user2);
|
通过非public修饰的有参构造器
1 2 3 4 5 6
| Constructor<?> declaredConstructor = userClass.getDeclaredConstructor(int.class, String.class); declaredConstructor.setAccessible(true); Object user3 = declaredConstructor.newInstance(20, "执笔"); System.out.println(user3);
|
反射访问类中成员
访问属性
1 2 3 4 5 6 7
| Field f = clazz对象.getDeclaredField(属性名);
f.setAccessible(true);
f.set(o,值); System.out.println(f.get(o));
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| Class<?> stuClass = Class.forName("com.hzy.study.reflection.Student");
Object o = stuClass.newInstance(); System.out.println(o.getClass());
Field age = stuClass.getField("age"); age.set(o, 20); System.out.println(age.get(o)); System.out.println(o);
Field name = stuClass.getDeclaredField("name"); name.setAccessible(true); name.set(o,"执笔"); System.out.println(name.get(o)); name.set(null,"执笔~"); System.out.println(name.get(null));
|
访问方法
1 2 3 4 5 6 7 8
| Method m =clazz.getDeclaredMethod(方法名,XX.class);
Object o = clazz.newlnstance();
m.setAccessible(true);
Object returnValue = m.invoke(o,实参列表);
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| Class<?> boosClass = Class.forName("com.hzy.study.reflection.Boss");
Object o = boosClass.newInstance();
Method hi = boosClass.getDeclaredMethod("hi", String.class); hi.invoke(o,"执笔");
Method say = boosClass.getDeclaredMethod("say", int.class, String.class, char.class); say.setAccessible(true); System.out.println(say.invoke(o, 100,"张三",'男')); System.out.println(say.invoke(null, 200, "李四",'男'));
Object reVal = say.invoke(null, 300, "王五", '男'); System.out.println("reVal 的运行类型= " + reVal.getClass());
|