反射机制
-
1.反射机制允许程序在执行期借助于Reflection API取得任何类的内部信息(比如成员变量,构造器,成员方法等等),并能操作对象的属性和方法。反射在设计模式和框架底层都会用到。
-
2.加载完类之后,在堆中就产生了一个Class类型的对象(一个类只有一个Class对象),这个对象包含了类的完整结构信息。通过这个对象得到类的结构。这个对象就像一面镜子,透过这个镜子看到类的结构,所以,形象的称之为:反射。
反射相关的主要类
1.java.lang.Class: 代表一个类,Class对象表示某个类加载后在堆中的对象。 2.java.lang.reflect.Method: 代表类的方法。 3.java.lang.reflect.Field: 代表类的成员变量。 4.java.lang.reflect.Constructor: 代表类的构造方法。
优点:可以动态的创建和使用对象(也是框架底层核心),使用灵活,没有反射机制,框架技术就失去底层支撑。
缺点:使用反射基本解释器执行,对执行速度有影响。
class类
1.Class也是类,因此也继承Object类 [类图] 2.Class类对象不是new出来的,而是系统创建的 [演示] 3.对于某个类的Class类对象,在内存中只有一份,因为类只加载一次 [演示] 4.每个类的实例都会记得自己是由哪个Class实例所生成 5.通过Class可以完整地得到一个类的完整结构,通过一系列API 6.Class对象是存放在堆的 7.类的字节码二进制数据,是放在方法区的,有的地方称为类的元数据(包括方法代码、变量名、方法名、访问权限等)
class类常用方法
方法名 | 描述 |
---|---|
static Class forName(String name) | 返回指定类名 name 的 Class 对象 |
Object newInstance() | 调用用省构造函数,返回该Class对象的一个实例 |
getName() | 返回此Class对象所表示的实体(类、接口、数组、基本类型等)名称 |
Class[] getInterfaces() | 获取当前Class对象的接口 |
ClassLoader getClassLoader() | 返回该类的加载器 |
Class getSuperclass() | 返回表示此Class所表示的实体的超类的Class |
Constructor[] getConstructors() | 返回一个包含某些Constructor对象的数组 |
Field[] getDeclaredFields() | 返回Field对象的一个数组 |
Method getMethod(String name, Class... paramTypes) | 返回一个Method对象,此对象的形参类型为paramType |
class<?> cls = class.forname(classallpath);//获取某一个类对应的class对象 system.out.println(cls)//显示cls对象是哪个类的class对象 system.out.println(cls.getclass())//输出cls运行类型 car car = (car)cls.newinstance();//创建一个对象实例
-
1.前提:已知一个类的全类名,且该类在类路径下,可通过Class类的静态方法forName()获取,可能抛出ClassNotFoundException,实例:class cls1 = Class.forName("java.lang.Cat"); 应用场景:多用于配置文件获取类全路径,加载类。
-
2.前提:若已知具体的类,通过类的class获取,该方式最为安全可靠,程序性能最高实例:class cls2 = Cat.class; 应用场景:多用于参数传递,比如通过反射得到对应构造器对象。
//1. Class.forName String classAllPath = "com.hspedu.Car"; //通过读取配置文件获取 Class<?> cls1 = Class.forName(classAllPath); System.out.println(cls1); //2. 类名.class , 应用场景: 用于参数传递 Class cls2 = Car.class; System.out.println(cls2); //3. 对象.getClass(), 应用场景,有对象实例 Car car = new Car(); Class cls3 = car.getClass(); System.out.println(cls3); //4. 通过类加载器【4 种】来获取到类的 Class 对象 //(1)先得到类加载器 car ClassLoader classLoader = car.getClass().getClassLoader(); //(2)通过类加载器得到 Class 对象 Class cls4 = classLoader.loadClass(classAllPath); System.out.println(cls4)
那些类型有class对象
-
1.外部类,成员内部类,静态内部类,局部内部类,匿名内部类
-
2.interface:接口
-
3.数组
-
4.enum:枚举
-
5.annotation:注解
-
6.基本数据类型
-
7.void
类加载
-
1.静态加载:编译时加载相关的类,如果没有则报错,依赖性太强
-
2.动态加载:运行时加载需要类的类,如果运行时不用该类,则不报错,依赖性降低了
-
加载(Loading):这是类加载过程的第一个阶段。在这个阶段,类加载器(ClassLoader)会根据完全限定名(包括包名和类名)来查找相应的二进制数据(通常是.class文件)。加载阶段完成后,类加载器会创建一个代表该类的java.lang.Class对象。
-
链接(Linking):验证(Verification):确保加载的类符合Java语言规范和JVM规范,验证类文件的正确性。
-
准备(Preparation):为类变量分配内存并设置类变量的默认初始值,这些内存是在方法区分配的。
-
解析(Resolution):将类、接口、字段和方法的符号引用转换为直接引用。
-
初始化(Initialization):这是类加载的最后一个阶段,也是类加载过程中唯一一个由程序员通过Java代码控制的阶段。在这个阶段,JVM会执行类构造器<clinit>()方法的过程,该方法是由编译器自动收集类中所有类变量的赋值动作和静态代码块中的语句合并产生的。
-
使用(Using):类加载完成后,类就可以被使用了,执行类中定义的业务逻辑。
-
卸载(Unloading):当一个类被加载后,它会在JVM的运行周期内一直存在,直到满足某些特定条件才会被卸载。类的卸载是由垃圾收集器完成的,当一个类没有任何实例存在,并且加载该类的类加载器实例被回收时,该类才会被卸载
反射获取类的结构信息
java.long.class
1.getName: 获取全类名
2.getSimpleName: 获取简单类名
3.getFields: 获取所有public修饰的属性,包含本类以及父类的
4.getDeclaredFields: 获取本类中所有属性
5.getDeclaredMethods: 获取本类中所有方法
6.getDeclaredMethod: 获取本类中所有方法
7.getConstructors: 获取所有public修饰的构造器,包含本类以及父类的
8.getDeclaredConstructors: 获取本类中所有构造器
9.getPackage: 以Package形式返回包信息
10.getSuperClass: 以Class形式返回父类信息
11.getInterfaces: 以Class[]形式返回接口类型
12.getAnnotations: 以Annotation[]形式返回注解信息
第二组: java.lang.reflect.Field 类
1.getModifiers: -int形式返回修饰符说明: 默认修饰符是0,public 是1,private 是2,protected 是4,static 是8,final 是16,public(1) + static (8) = 9
2.getType: -Class形式返回类型
3.getName: 返回属性名
第三组: java.lang.reflect.Method 类
1.getModifiers: -int形式返回修饰符说明: 默认修饰符是0,public 是1,private 是2,protected 是4,static 是8,final 是16,public(1) + static (8) = 9
2.getReturnType: -Class形式获取 返回类型
3.getName: 返回方法名
4.getParameterTypes: -Class[] 返回参数类型数组
java.lang.reflect.Constructor 类
1.getModifiers: 以int形式返回修饰符
2.getName: 返回构造器名(全类名)
3.getParameterTypes: 以Class[]返回参数类型数组
通过反射创建对象
1.方式一:调用类中的public修饰的无参构造器
2.方式二:调用类中的指定构造器
3.Class类相关方法
newInstance:调用类中的无参构造器,获取对应类的对象getConstructor(Class<?> cls):根据参数列表获取对应的public构造器对象
getDeclaredConstructor(Class<?> cls):根据参数列表,获取对应的所有构造器对象
4.Constructor类相关方法
setAccessible:暴破
newInstance(Object... obj):调用构造器
通过反射访问类的成员变量
-
根据属性名获取Field对象
Field f = clazz对象.getDeclaredField(属性名);
-
暴破:f.setAccessible(true); //f是Field
-
访问
f.set(o, value); sysf(f.get(o));
-
如果是静态属性,则set和get中的参数o,可以写成null
通过反射访问方法
1.根据方法名和参数列表获取Method方法对象:Method m = clazz.getDeclaredMethod(方法名, XX.class);
2.获取对象:Object o=clazz.newInstance();
3.暴破:m.setAccessible(true);
4.访问:Object returnValue = m.invoke(o, 实参列表);
5.注意:如果是静态方法,则invoke的参数o,可以写成null!