获取 Class 类对象的六种方式![]()
//1. Class.forName String classfullpath = "com.edu.car"; Class cls = Class.forName(classfullpath); System.out.println(cls);
Constructor constructor2 = cls.getConstructor(String.class, int.class); //2.类名.class,应用场景,参数传递 Class cls2 = Car.class; System.out.println(cls2);
//3.对象.getClass(),应用场景,有对象实例,运行类型 Car car = new Car(); Class cls3 = car.getClass();
//4. 通过类加载器【4 种】来获取到类的 Class 对象 //(1)先得到类加载器 car ClassLoader classLoader = car.getClass().getClassLoader(); //(2)通过类加载器得到 Class 对象 Class cls4 = classLoader.loadClass(classfullpath); System.out.println(cls4); 对于类加载器classloader,还可以用来给加载类所在目录下的资源文件 https://www.cnblogs.com/macwhirr/p/8116583.html
不同的阶段有不同的获取Class对象方法
哪些类型有Class对象1.外部类,成员内部类,静态内部类,局部内部类,匿名内部类2.interface:接口3.数组4.enum:枚举5.annotation:注解6.基本数据类型7.void
类的动态加载和静态加载new创建对象的方式称作为 静态加载 ,编译时加载相关的类,如果不存在该类,编译时会报错使用Class.forName("XXX")称作为 动态加载 ,运行时加载类,如果不存在该类,在编译时不会检查,直到运行到要加载该类的时候,才会报错,如果运行时,不使用该类仍然不会报错类加载时机:![]()
类加载流程图:
类加载的五个部分:一、加载阶段由类加载器完成,将字节码从不同的数据源(可能是class文件,也可能是jar包或者网络)转化为二进制字节流加载到内存【方法区】中
二、连接阶段--验证:为了确保class文件的字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身的安全包括:文件格式验证(class文件是否cafebabe开头),元数据验证,字节码验证和符号引用验证可以考虑使用-Xverify:none参数来关闭大部分的类验证措施,缩短虚拟机类加载的时间
二、连接阶段--准备JVM会在该阶段对 静态变量,分配内存并默认初始化(对应数据类型的默认初始值,如0,0L,null,false等)这些变量所使用的内存都将在方法区中进行分配class A { //属性-成员变量- 字段 // 类加载的链接阶段-准备 //1. n1 是实例属性, 不是静态变量,因此在准备阶段,是不会分配内存 //2. n2 是静态变量,分配内存 n2 是默认初始化 0 ,而不是 20 //3. n3 是 static final 是常量, 他和静态变量不一样, 因为一旦赋值就不变 n3 = 30 public int n1 = 10; public static int n2 = 20; public static final int n3 = 30; }
三、连接阶段--解析虚拟机将常量池内的符号引用替换为直接引用的过程
四、initialization(初始化)1.到该阶段才是真正开始执行类中定义的Java程序,是执行<client>()方法的过程2.<client>()方法是由编译器按语句在原文中出现的顺序,依次自动收集类中的所有 静态变量的赋值动作和静态代码块中的代码,并进行合并3.虚拟机会保证一个类的<client>()方法在多线程环境下被正确的加锁,同步。如果多个线程同时去初始化一个类,那么只会有一个线程去执行该类的<client>()方法,其他线程需要阻塞等待,直到活动进行执行<client>()方法完毕
通过反射(Class对象)获得类的结构信息第一组:Java.lang.Class![]()
//第一组方法API @Test public void api_01() throws ClassNotFoundException, NoSuchMethodException { //得到Class对象 Class<?> personCls = Class.forName("com.hspedu.reflection.Person"); //getName:获取全类名 System.out.println(personCls.getName());//com.hspedu.reflection.Person //getSimpleName:获取简单类名 System.out.println(personCls.getSimpleName());//Person //getFields:获取所有public修饰的属性,包含本类以及父类的 Field[] fields = personCls.getFields(); for (Field field : fields) {//增强for System.out.println("本类以及父类的属性=" + field.getName()); } //getDeclaredFields:获取本类中所有属性 Field[] declaredFields = personCls.getDeclaredFields(); for (Field declaredField : declaredFields) { System.out.println("本类中所有属性=" + declaredField.getName()); } //getMethods:获取所有public修饰的方法,包含本类以及父类的 Method[] methods = personCls.getMethods(); for (Method method : methods) { System.out.println("本类以及父类的方法=" + method.getName()); } //getDeclaredMethods:获取本类中所有方法 Method[] declaredMethods = personCls.getDeclaredMethods(); for (Method declaredMethod : declaredMethods) { System.out.println("本类中所有方法=" + declaredMethod.getName()); } //getConstructors: 获取所有public修饰的构造器,包含本类 Constructor<?>[] constructors = personCls.getConstructors(); for (Constructor<?> constructor : constructors) { System.out.println("本类的构造器=" + constructor.getName()); } //getDeclaredConstructors:获取本类中所有构造器 Constructor<?>[] declaredConstructors = personCls.getDeclaredConstructors(); for (Constructor<?> declaredConstructor : declaredConstructors) { System.out.println("本类中所有构造器=" + declaredConstructor.getName());//这里老师只是输出名 } //getPackage:以Package形式返回 包信息 System.out.println(personCls.getPackage());//com.hspedu.reflection //getSuperClass:以Class形式返回父类信息 Class<?> superclass = personCls.getSuperclass(); System.out.println("父类的class对象=" + superclass);// //getInterfaces:以Class[]形式返回接口信息 Class<?>[] interfaces = personCls.getInterfaces(); for (Class<?> anInterface : interfaces) { System.out.println("接口信息=" + anInterface); } //getAnnotations:以Annotation[] 形式返回注解信息 Annotation[] annotations = personCls.getAnnotations(); for (Annotation annotation : annotations) { System.out.println("注解信息=" + annotation);//注解 } }
第二组:Java.lang.reflect.Field类
getType返回属性所对应类的Class对象
第三组:Java.lang.reflect.Method类
第四组:Java.lang.reflect.Constructor类
@Test public void api_02() throws ClassNotFoundException, NoSuchMethodException { //得到Class对象 Class<?> personCls = Class.forName("com.hspedu.reflection.Person"); //getDeclaredFields:获取本类中所有属性 //规定 说明: 默认修饰符 是0 , public 是1 ,private 是 2 ,protected 是 4 , static 是 8 ,final 是 16 Field[] declaredFields = personCls.getDeclaredFields(); for (Field declaredField : declaredFields) { System.out.println("本类中所有属性=" + declaredField.getName() + " 该属性的修饰符值=" + declaredField.getModifiers() + " 该属性的类型=" + declaredField.getType()); } //getDeclaredMethods:获取本类中所有方法 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); } } //getDeclaredConstructors:获取本类中所有构造器 Constructor<?>[] declaredConstructors = personCls.getDeclaredConstructors(); for (Constructor<?> declaredConstructor : declaredConstructors) { System.out.println("===================="); System.out.println("本类中所有构造器=" + declaredConstructor.getName());//这里老师只是输出名 Class<?>[] parameterTypes = declaredConstructor.getParameterTypes(); for (Class<?> parameterType : parameterTypes) { System.out.println("该构造器的形参类型=" + parameterType); } } }
通过反射构建对象(私有构造【爆破】和共有构造)的方法:
1.调用无参构造://调用类中的无参构造器,必须是public修饰 Class cls = Class.forName(classpath); //(2) 通过cls 得到你加载的类 com.edu.Cat 的对象实例 Object o = cls.newInstance();
2.通过Constructor调用有参构造
//使用getConstructor获取构造器,构造函数不能是private Constructor constructor2 = cls.getConstructor(String.class, int.class); Object o1 = constructor2.newInstance("a", 1);
//要获得private的构造器对象,使用getDeclaredConstructor方法 Constructor declaredConstructor = cls.getDeclaredConstructor(String.class, int.class); //但是仍然不可以new对象,因为构造器是私有的 Object a = declaredConstructor.newInstance("a", 1); //在获取了构造器对象declaredConstructor 之后,需要关闭安全访问检查,在newInstance declaredConstructor.setAccessible(true); Object a = declaredConstructor.newInstance("a", 1);
通过反射获取属性对象(私有属性【爆破】和共有属性)的方法:
//getField不能得到私有的属性对象,可以使用getDeclaredField(属性名) Object o = stuClass.newInstance();//o 的运行类型就是 Student Class<?> stuClass = Class.forName("com.hspedu.reflection.Student"); //使用反射操作私有属性 name 属性 Field name = stuClass.getDeclaredField("name"); //对 name 进行暴破, 可以操作 private 属性 name.setAccessible(true); name.set(o, "xxx"); //如果name还是static修饰,可以将o写成null
通过反射获取方法对象(私有方法【爆破】和共有方法)的方法:
//通过方法名和参数列表来获取method对象,通过getDeclaredMethod方法获取私有方法对象 Class<?> bossCls = Class.forName("com.hspedu.reflection.Boss"); Object o = bossCls.newInstance(); //调用 public 的 hi 方法 //Method hi = bossCls.getMethod("hi", String.class);//OK //调用私有private的hi方法 Method hi = bossCls.getDeclaredMethod("hi", String.class);//OK hi.invoke(o, "教育~"); //同样如果hi方法是static修饰,你仍可以将invode方法中o写成null