反射
-
reflect 高级特性
-
反射 是框架的灵魂;
-
反射:运行过程中 动态获取类的信息(获取类对象) 和对类进行操作的机制;
-
Java的程序的执行:
-
1 编译 .java .class字节码文件 Student.java->Student.class
-
2 运行 .class文件由类加载器 加载进JVM内存 形式 Class类型 类对象;
-
类对象{成员变量,构造器,方法},每一个成分放大来看,他们都是对象;
-
反射的使用
1,获取类对象
/** * 1,获取类对象的 三种方式 * * @throws ClassNotFoundException */ private static void method1() throws ClassNotFoundException { //1, 类名.class Class<Monkey> monkeyClass = Monkey.class; //2,对象名.getClass(); Monkey monkey = null; Class<? extends Monkey> aClass = monkey.getClass(); //3,类的全路径 包名+类名 (常用) Class<?> aClass1 = Class.forName("com.edu.www.day0509.Monkey"); Class<?> aClass2 = Class.forName("com.edu.www.day0509.Monkey"); //一个类的类对象只有一个 System.out.println(monkeyClass == aClass); System.out.println(aClass1 == aClass); System.out.println(aClass1 == aClass2); }
2,构造器的操作
/** * 对构造器的操作 * * @throws ClassNotFoundException * @throws NoSuchMethodException * @throws InstantiationException * @throws IllegalAccessException * @throws InvocationTargetException */ private static void method3() throws ClassNotFoundException, NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException { Class<?> aClass = Class.forName("com.edu.www.day0509.Monkey"); //Constructor构造器类型 // getConstructors只获取public修饰的构造器对象 Constructor<?>[] constructors = aClass.getConstructors(); System.out.println(constructors.length); // getDeclaredConstructors 获取本类声明的所有构造器对象 Constructor<?>[] declaredConstructors = aClass.getDeclaredConstructors(); System.out.println(declaredConstructors.length); //getConstructor 只获取public修饰的某个构造器对象 Constructor<?> constructor1 = aClass.getConstructor(String.class); // Constructor<?> constructor2 = aClass.getConstructor(int.class); Constructor<?> constructor3 = aClass.getConstructor(int.class, String.class); Object instance = constructor3.newInstance(11, "猴子3"); System.out.println(instance); Constructor<?> constructor4 = aClass.getConstructor(); //getDeclaredConstructor 所有修饰符的某个构造器对象 Constructor<?> declaredConstructor1 = aClass.getDeclaredConstructor(String.class); //使用构造器创建对象 实例(对象 instance) Object o = declaredConstructor1.newInstance("猴子1"); System.out.println(o); Constructor<?> declaredConstructor2 = aClass.getDeclaredConstructor(int.class); declaredConstructor2.setAccessible(true); Object o2 = declaredConstructor2.newInstance(12); System.out.println(o2); }
创建对象的简易方式
/** * 创建对象简易方式 * @throws ClassNotFoundException * @throws InstantiationException * @throws IllegalAccessException */ private static void method4() throws ClassNotFoundException, InstantiationException, IllegalAccessException { Class<?> aClass = Class.forName("com.edu.www.day0509.Monkey"); //newInstance直接创建对象 其实是调用无参构造器对象去创建对象 Object o = aClass.newInstance(); System.out.println(o); }
3,对成员变量的操作
/** * 对成员变量的操作 * @throws ClassNotFoundException * @throws InstantiationException * @throws IllegalAccessException * @throws NoSuchFieldException */ private static void method5() throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchFieldException { Class<?> aClass = Class.forName("com.edu.www.day0509.Student"); Object o = aClass.newInstance(); System.out.println(o); //Field 成员变量类型 //getFields只获取public修饰成员变量 也包含继承的 Field[] fields = aClass.getFields(); System.out.println(fields.length); // getDeclaredFields只获取本类声明的成员变量对象 Field[] declaredFields = aClass.getDeclaredFields(); System.out.println(declaredFields.length); // getField 只获取public修饰成员变量 也包含继承的 // Field id = aClass.getField("id"); // getDeclaredField 根据成员变量的名称 获取本类声明的某个成员变量对象 Field declaredField1 = aClass.getDeclaredField("id"); Field declaredField2 = aClass.getDeclaredField("name"); declaredField1.setAccessible(true); declaredField2.setAccessible(true); //赋值的 declaredField1.set(o, 1001); declaredField2.set(o, "张三"); System.out.println(o); }
类的加载时机
-
类是按需加载的,用到的时候才加载
-
某个类只会被加载一次的
类加载器
-
核心类加载器(启动类加载器) bootstrapClassLoader
-
本地语言实现的
-
核心包中核心类型
-
-
扩展类加载器 platformClassLoder 平台类加载器
-
扩展类
-
-
应用类加载器 ApplicationClassLoader
-
自定义的类型都是ACL加载
-
-
其他类加载器
双亲委派模型:如果一个类加载器收到了类加载的请求,它首先不会自己去尝试加载这个类,而是把这个请求委派给父类加载器去完成,每一个层次的加载器都是如此,因此所有的类加载请求都会传给顶层的启动类加载器,只有当父加载器反馈自己无法完成该加载请求(该加载器的搜索范围中没有找到对应的类)时,子加载器才会尝试自己去加载。
使用双亲委派模型的好处在于Java类随着它的类加载器一起具备了一种带有优先级的层次关系。例如类java.lang.Object,它存在在rt.jar中,无论哪一个类加载器要加载这个类,最终都是委派给处于模型最顶端的Bootstrap ClassLoader进行加载,因此Object类在程序的各种类加载器环境中都是同一个类。相反,如果没有双亲委派模型而是由各个类加载器自行加载的话,如果用户编写了一个java.lang.Object的同名类并放在ClassPath中,那系统中将会出现多个不同的Object类,程序将混乱。因此,如果开发者尝试编写一个与rt.jar类库中重名的Java类,可以正常编译,但是永远无法被加载运行。