java反射主要从如下几个方面理解php
Java程序在运行时,Java运行时系统一直对全部的对象进行所谓的运行时类型标识,即所谓的RTTI。这项信息纪录了每一个对象所属的类。虚拟机一般使用运行时类型信息选准正确方法去执行,用来保存这些类型信息的类是Class类。Class类封装一个对象和接口运行时的状态,当装载类时,Class类型的对象自动建立。
简单解释上面一段话
一、Class类也是类的一种,只是名字和class关键字高度类似。Java是大小写敏感的语言。
二、Class类的对象内容是你建立的类的类型信息,好比你建立一个shapes类,那么,Java会生成一个内容是shapes的Class类的对象。
三、Class类的对象不能像普通类同样,以 new shapes() 的方式建立,它的对象只能由JVM建立,由于这个类没有public构造函数。
四、Class类的做用是运行时提供或得到某个对象的类型信息。java
全部java类都是继承了object这个类,在object这个类中有一个方法:getclass().这个方法是用来取得该类已经被实例化了的对象的该类的引用,这个引用指向的是Class类的对象。python
一、Class类的forName方法bootstrap
Class<?> aClass = Class.forName("com.sl.reflect.Student");
二、对象的getClass()方法数组
Student student = new Student(); Class<? extends Student> aClass1 = student.getClass();
三、使用类名加.class函数
Class classes = Student.class.getClass();
四、经过ClassLoader对象的loadClass()方法测试
Class<?> aClass2 = ClassLoader.getSystemClassLoader().loadClass("com.sl.reflect.Student");
敲黑板调用newInstance()方法时,调用的是无参构造器,因此每一个类中必定要声明一个无参构造器ui
类装载器是用来把类(class)装载进 JVM 的。JVM 规范定义了两种类型的类装载器:启动类装载器(bootstrap)和用户自定义装载器(user-defined class loader)。 JVM在运行时会产生3个类加载器组成的初始化加载器层次结构 ,以下图所示:this
//一、获取系统类的加载器 ClassLoader classLoader = ClassLoader.getSystemClassLoader(); System.out.println(classLoader); //2. 获取系统类加载器的父类加载器(扩展类加载器,能够获取). classLoader = classLoader.getParent(); System.out.println(classLoader); //3. 获取扩展类加载器的父类加载器(引导类加载器,不可获取). classLoader = classLoader.getParent(); System.out.println(classLoader);
注意系统类加载器能够加载当前项目src目录下面的全部类,若是文件也放在src下面,也能够用类加载器来加载调用 getResourceAsStream 获取类路径下的文件对应的输入流。spa
//文件夹在src下 InputStream resourceAsStream = ClassLoader.getSystemClassLoader().getResourceAsStream("text1.txt"); //文件夹在包名下 InputStream resourceAsStream1 = ClassLoader.getSystemClassLoader().getResourceAsStream("com/sl/reflect/text2.txt");
Java反射机制主要提供了如下功能
Student测试类
/** * @author shuliangzhao * @Title: Student * @ProjectName design-parent * @Description: TODO * @date 2019/6/15 23:08 */ public class Student { private String name; private Integer age; public Student() { } public Student(String name,Integer age) { this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } }
public static void testMethod() throws Exception { Class<Student> aClass = (Class<Student>) Class.forName("com.sl.reflect.Student"); //1.获取方法 // 获取取clazz对应类中的全部方法--方法数组(一) // 不能获取private方法,而且获取从父类继承来的全部方法 Method[] methods = aClass.getMethods(); for (Method method:methods) { System.out.println(method); } System.out.println("================================"); //2.获取方法 // 获取取clazz对应类中的全部方法--方法数组(一) // 不能获取private方法,不获取从父类继承来的全部方法 Method[] declaredMethods = aClass.getDeclaredMethods(); for (Method method:declaredMethods) { System.out.println(method); } System.out.println("================================="); // 1.3.获取指定的方法 // 须要参数名称和参数列表,无参则不须要写 // 对于方法public void setName(String name) { } Method method = aClass.getDeclaredMethod("setName", String.class); System.out.println(method); // 而对于方法public void setAge(int age) { } method = aClass.getDeclaredMethod("setAge", Integer.class); System.out.println(method); // 这样写是获取不到的,若是方法的参数类型是int型 // 若是方法用于反射,那么要么int类型写成Integer: public void setAge(Integer age) { } // 要么获取方法的参数写成int.class //2.执行方法 // invoke第一个参数表示执行哪一个对象的方法,剩下的参数是执行方法时须要传入的参数 Object obje = aClass.newInstance(); method.invoke(obje,2); //若是一个方法是私有方法,第三步是能够获取到的,可是这一步却不能执行 //私有方法的执行,必须在调用invoke以前加上一句method.setAccessible(true); } /** * 把类对象和类方法名做为参数,执行方法 * * 把全类名和方法名做为参数,执行方法 * 可变参数能够放数组 * @param obj: 方法执行的那个对象. * @param methodName: 类的一个方法的方法名. 该方法也多是私有方法. * @param args: 调用该方法须要传入的参数 * @return: 调用方法后的返回值 * */ public Object invoke(Object obj, String methodName, Object ... args) throws Exception{ //1. 获取 Method 对象 // 由于getMethod的参数为Class列表类型,因此要把参数args转化为对应的Class类型。 Class [] parameterTypes = new Class[args.length]; for(int i = 0; i < args.length; i++){ parameterTypes[i] = args[i].getClass(); System.out.println(parameterTypes[i]); } Method method = obj.getClass().getDeclaredMethod(methodName, parameterTypes); //若是使用getDeclaredMethod,就不能获取父类方法,若是使用getMethod,就不能获取私有方法 // //2. 执行 Method 方法 //3. 返回方法的返回值 return method.invoke(obj, args); }
public static void testField() throws Exception { Class<Student> aClass = (Class<Student>) Class.forName("com.sl.reflect.Student"); //1.获取字段 // 1.1 获取全部字段 -- 字段数组 // 能够获取公用和私有的全部字段,但不能获取父类字段 Field[] declaredFields = aClass.getDeclaredFields(); for (Field field:declaredFields) { System.out.println(field); } System.out.println("============================="); // 1.2获取指定字段 Field field = aClass.getDeclaredField("name"); System.out.println(field.getName()); System.out.println("=============================="); Student student = new Student(); //若是字段是私有的,无论是读值仍是写值,都必须先调用setAccessible(true)方法 field.setAccessible(true); student.setAge(1); student.setName("张三"); //2.使用字段 // 2.1获取指定对象的指定字段的值 Object o = field.get(student); System.out.println(o); System.out.println("=========================="); // 2.2设置指定对象的指定对象Field值 field.set(student, "DEF"); System.out.println(student.getName()); }
public static void testConstructor() throws Exception{ Class<Student> aClass = (Class<Student>) Class.forName("com.sl.reflect.Student"); //1. 获取 Constructor 对象 // 1.1 获取所有 Constructor<?>[] constructors = aClass.getConstructors(); for (Constructor constructor:constructors) { System.out.println(constructor); } System.out.println("============================"); // 1.2获取某一个,须要参数列表 Constructor<Student> constructor = aClass.getConstructor(String.class, Integer.class); System.out.println(constructor); System.out.println("============================"); //2. 调用构造器的 newInstance() 方法建立对象 Object obj = constructor.newInstance("zhagn", 1); }
@Retention(RetentionPolicy.RUNTIME) @Target(value={ElementType.METHOD}) public @interface AgeValidator { public int min(); public int max(); } public static void testAnnotation() throws Exception{ Class<?> aClass = Class.forName("com.sl.reflect.Student"); Object o = aClass.newInstance(); Method method = aClass.getDeclaredMethod("setAge", Integer.class); int val = 6; AgeValidator annotation = method.getAnnotation(AgeValidator.class); if (annotation != null) { if (annotation instanceof AgeValidator) { AgeValidator ageValidator = annotation; if (val < ageValidator.min() || val > ageValidator.max()) { throw new RuntimeException("年龄非法"); } } } method.invoke(o,20); System.out.println(o); }