java反射机制 [TOC]
反射的概述 1.本章的主要内容
2.关于反射的理解
3.体会反射机制的“动态性” 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 @Test public void test2 () { for (int i = 0 ;i < 100 ;i++){ int num = new Random().nextInt(3 ); String classPath = "" ; switch (num){ case 0 : classPath = "java.util.Date" ; break ; case 1 : classPath = "java.lang.Object" ; break ; case 2 : classPath = "com.atguigu.java.Person" ; break ; } try { Object obj = getInstance(classPath); System.out.println(obj); } catch (Exception e) { e.printStackTrace(); } } } public Object getInstance (String classPath) throws Exception { Class clazz = Class.forName(classPath); return clazz.newInstance(); }
4.反射机制能提供的功能
5.相关API
java.lang.Class:反射的源头
java.lang.reflect.Method
java.lang.reflect.Field
java.lang.reflect.Constructor
….
Class类的理解与获取Class的实例 1.Class类的理解 1.类的加载过程: 程序经过javac.exe命令以后,会生成一个或多个字节码文件(.class结尾)。 接着我们使用java.exe命令对某个字节码文件进行解释运行。相当于将某个字节码文件 加载到内存中。此过程就称为类的加载。加载到内存中的类,我们就称为运行时类,此 运行时类,就作为Class的一个实例。
2.换句话说,Class的实例就对应着一个运行时类。 3.加载到内存中的运行时类,会缓存一定的时间。在此时间之内,我们可以通过不同的方式来获取此运行时类。 2.获取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 Class clazz1 = Person.class; System.out.println(clazz1); Person p1 = new Person(); Class clazz2 = p1.getClass(); System.out.println(clazz2); Class clazz3 = Class.forName("com.atguigu.java.Person" ); System.out.println(clazz3); System.out.println(clazz1 == clazz2); System.out.println(clazz1 == clazz3); ClassLoader classLoader = ReflectionTest.class.getClassLoader(); Class clazz4 = classLoader.loadClass("com.atguigu.java.Person" ); System.out.println(clazz4); System.out.println(clazz1 == clazz4);
3.总结:创建类的对象的方式? 方式一:new + 构造器 方式二:要创建Xxx类的对象,可以考虑:Xxx、Xxxs、XxxFactory、XxxBuilder类中查看是否有 静态方法的存在。可以调用其静态方法,创建Xxx对象。 方式三:通过反射
4.Class实例可以是哪些结构的说明
了解ClassLoader 1.类的加载过程—-了解
2.类的加载器的作用
3.类的加载器的分类
4.Java类编译、运行的执行的流程
5.使用Classloader加载src目录下的配置文件 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 @Test public void test2 () throws Exception { Properties pros = new Properties(); ClassLoader classLoader = ClassLoaderTest.class.getClassLoader(); InputStream is = classLoader.getResourceAsStream("jdbc1.properties" ); pros.load(is); String user = pros.getProperty("user" ); String password = pros.getProperty("password" ); System.out.println("user = " + user + ",password = " + password); }
反射应用一:创建运行时类的对象 1.代码举例 1 2 3 4 Class<Person> clazz = Person.class; Person obj = clazz.newInstance(); System.out.println(obj);
2.说明
1.运行时类必须提供空参的构造器 2.空参的构造器的访问权限得够。通常,设置为public。
在javabean中要求提供一个public的空参构造器。原因:
1.便于通过反射,创建运行时类的对象 2.便于子类继承此运行时类时,默认调用super()时,保证父类此构造器 反射应用二:获取运行时类的完整结构
我们可以通过反射,获取对应的运行时类中所有的属性、方法、构造器、父类、接口、父类的泛型、包、注解、异常等。。。。
典型代码: 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 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 @Test public void test1 () { Class clazz = Person.class; Field[] fields = clazz.getFields(); for (Field f : fields){ System.out.println(f); } System.out.println(); Field[] declaredFields = clazz.getDeclaredFields(); for (Field f : declaredFields){ System.out.println(f); } } @Test public void test1 () { Class clazz = Person.class; Method[] methods = clazz.getMethods(); for (Method m : methods){ System.out.println(m); } System.out.println(); Method[] declaredMethods = clazz.getDeclaredMethods(); for (Method m : declaredMethods){ System.out.println(m); } } @Test public void test1 () { Class clazz = Person.class; Constructor[] constructors = clazz.getConstructors(); for (Constructor c : constructors){ System.out.println(c); } System.out.println(); Constructor[] declaredConstructors = clazz.getDeclaredConstructors(); for (Constructor c : declaredConstructors){ System.out.println(c); } } @Test public void test2 () { Class clazz = Person.class; Class superclass = clazz.getSuperclass(); System.out.println(superclass); } @Test public void test3 () { Class clazz = Person.class; Type genericSuperclass = clazz.getGenericSuperclass(); System.out.println(genericSuperclass); } @Test public void test4 () { Class clazz = Person.class; Type genericSuperclass = clazz.getGenericSuperclass(); ParameterizedType paramType = (ParameterizedType) genericSuperclass; Type[] actualTypeArguments = paramType.getActualTypeArguments(); System.out.println(((Class)actualTypeArguments[0 ]).getName()); } @Test public void test5 () { Class clazz = Person.class; Class[] interfaces = clazz.getInterfaces(); for (Class c : interfaces){ System.out.println(c); } System.out.println(); Class[] interfaces1 = clazz.getSuperclass().getInterfaces(); for (Class c : interfaces1){ System.out.println(c); } } @Test public void test6 () { Class clazz = Person.class; Package pack = clazz.getPackage(); System.out.println(pack); } @Test public void test7 () { Class clazz = Person.class; Annotation[] annotations = clazz.getAnnotations(); for (Annotation annos : annotations){ System.out.println(annos); } }
反射应用三:调用运行时类的指定结构 调用指定的属性: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 @Test public void testField1 () throws Exception { Class clazz = Person.class; Person p = (Person) clazz.newInstance(); Field name = clazz.getDeclaredField("name" ); name.setAccessible(true ); name.set(p,"Tom" ); System.out.println(name.get(p)); }
调用指定的方法: 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 @Test public void testMethod () throws Exception { Class clazz = Person.class; Person p = (Person) clazz.newInstance(); Method show = clazz.getDeclaredMethod("show" , String.class); show.setAccessible(true ); Object returnValue = show.invoke(p,"CHN" ); System.out.println(returnValue); System.out.println("*************如何调用静态方法*****************" ); Method showDesc = clazz.getDeclaredMethod("showDesc" ); showDesc.setAccessible(true ); Object returnVal = showDesc.invoke(Person.class); System.out.println(returnVal); }
调用指定的构造器: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 @Test public void testConstructor () throws Exception { Class clazz = Person.class; Constructor constructor = clazz.getDeclaredConstructor(String.class); constructor.setAccessible(true ); Person per = (Person) constructor.newInstance("Tom" ); System.out.println(per); }
反射应用四:动态代理 1.代理模式的原理: 使用一个代理将对象包装起来, 然后用该代理对象取代原始对象。任何对原始对象的调用都要通过代理。代理对象决定是否以及何时将方法调用转到原始对象上。
2.静态代理 2.1 举例: 实现Runnable接口的方法创建多线程。 Class MyThread implements Runnable{} //相当于被代理类 Class Thread implements Runnable{} //相当于代理类 main(){ MyThread t = new MyThread(); Thread thread = new Thread(t); thread.start();//启动线程;调用线程的run() }
2.2 静态代理的缺点: ① 代理类和目标对象的类都是在编译期间确定下来,不利于程序的扩展。 ② 每一个代理类只能为一个接口服务,这样一来程序开发中必然产生过多的代理。
3.动态代理的特点: 动态代理是指客户通过代理类来调用其它对象的方法,并且是在程序运行时根据需要动态创建目标类的代理对 象。
4.动态代理的实现 4.1 需要解决的两个主要问题: 问题一:如何根据加载到内存中的被代理类,动态的创建一个代理类及其对象。 (通过Proxy.newProxyInstance()实现) 问题二:当通过代理类的对象调用方法a时,如何动态的去调用被代理类中的同名方法a。 (通过InvocationHandler接口的实现类及其方法invoke())
4.2 代码实现: 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 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 interface Human { String getBelief () ; void eat (String food) ; } class SuperMan implements Human { @Override public String getBelief () { return "I believe I can fly!" ; } @Override public void eat (String food) { System.out.println("我喜欢吃" + food); } } class HumanUtil { public void method1 () { System.out.println("====================通用方法一====================" ); } public void method2 () { System.out.println("====================通用方法二====================" ); } } class ProxyFactory { public static Object getProxyInstance (Object obj) { MyInvocationHandler handler = new MyInvocationHandler(); handler.bind(obj); return Proxy.newProxyInstance(obj.getClass().getClassLoader(),obj.getClass().getInterfaces(),handler); } } class MyInvocationHandler implements InvocationHandler { private Object obj; public void bind (Object obj) { this .obj = obj; } @Override public Object invoke (Object proxy, Method method, Object[] args) throws Throwable { HumanUtil util = new HumanUtil(); util.method1(); Object returnValue = method.invoke(obj,args); util.method2(); return returnValue; } } public class ProxyTest { public static void main (String[] args) { SuperMan superMan = new SuperMan(); Human proxyInstance = (Human) ProxyFactory.getProxyInstance(superMan); String belief = proxyInstance.getBelief(); System.out.println(belief); proxyInstance.eat("四川麻辣烫" ); System.out.println("*****************************" ); NikeClothFactory nikeClothFactory = new NikeClothFactory(); ClothFactory proxyClothFactory = (ClothFactory) ProxyFactory.getProxyInstance(nikeClothFactory); proxyClothFactory.produceCloth(); } }
体会:反射的动态性。