张孝祥系列
《thinking in java 》Bruce Eckel
反射原理与实战
要理解反射得要弄清楚关键字 Class ,因为 反射就是:
通过类的字节码把类中的各种成分(方法、成员变量以及类与包等)动态映射成相应的java类(Method、Field等),而类的字节码正是用 Class来表示的。
首先,从宏观上来了解Class。 类 是对具有相似特征的对象们的一种抽象,表示一类事物,一种东西。比如,"人" 这个 类 - 相似特征:有眼睛,鼻子; 会说话。Java的字节码也是一类事物,也具有一些相似特征:都是由 pacakge、Method以及 Field等成分组成。我们用 Class 这个关键字来表示这样一类 字节码 事物。
再 从功能上来了解Class。java 程序中要用到某个具体类型的对象时:首先从硬盘上(或者网络等其他地方)把该类的二进制代码加载到内存中来,再用这份二进制代码复制一个个具体所用到的对象。程序中要用到多小个类,那么内存中就得加载多少份字节码。
定义:通过类的字节码把类中的各种成分(方法、成员变量以及类与包等)动态映射成相应的java类(Method、Field等)。 程序在编译时并不知道具体要处理的类时什么,但是需要该类的一些方法与属性,这在一些开源框架比如说 Spring中用的很多(纯属瞎猜,有待后续源码 分析进一步验证)。通常在配置文件中配置相关的类信息,Sping容器通过反射获取并操作该类的相关方法与属性。
package reflect; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; /** * Created by pengyucheng on 16-4-13. * 一、Class 类认识 二、 反射 * 定义:通过类的字节码把类中的各种成分(方法、成员变量以及类与包等)动态映射成相应的java类(Method、Field等) */ public class ReflectTest { public static void main(String[] args) throws Exception { String str1 = 理解Class(); 构造方法反射(); 成员变量的反射(); 普通方法的反射(args[0], "abc"); } /** * 反射前奏: Class的理解之获取类字节码(这里以String类为例)的三种方式 * String str = "123456" * 1、str.getClass() * 2、Class.forName("java.lang.String") : 获取类的字节码 1、有则从JVM中获取 2、没有则从硬盘上加载并放缓存到JVM中 * 3、String.class * @throws ClassNotFoundException */ private static String 理解Class() throws ClassNotFoundException { String str1 = "abc"; Class cls1 = str1.getClass(); Class cls2 = Class.forName("java.lang.String"); //用的最多,动态获取类的字节码 Class cls3 = String.class; System.out.println(cls1==cls2); System.out.println(cls1==cls3); // 具体数据类型(这里是String类型)的字节码在内存中只有一份 System.out.println(cls1.isPrimitive()); System.out.println(int.class.isPrimitive()); System.out.println(int.class == Integer.class); System.out.println(int.class == Integer.TYPE); System.out.println(int[].class.isPrimitive()); System.out.println(int[].class.isArray()); } /** * 构造方法的反射 之 用放射模拟 new String(new StringBuffer("abc")); * @throws NoSuchMethodException * @throws InstantiationException * @throws IllegalAccessException * @throws java.lang.reflect.InvocationTargetException */ private static void 构造方法反射() throws NoSuchMethodException, InstantiationException, IllegalAccessException, java.lang.reflect.InvocationTargetException { Constructor constructor = String.class.getConstructor(StringBuffer.class); String str = (String)constructor.newInstance(new StringBuffer("abc")); System.out.println(str.charAt(2)); //简写-省略中间获取 Constructor的过程 String.class.newInstance(); } /** * 成员变量的反射 * * 暴力反射:private属性的访问。 * @throws Exception */ private static void 成员变量的反射() throws Exception { ReflectPoint rf = new ReflectPoint(2,3); Field fieldx = rf.getClass().getField("x"); System.out.print(fieldx.get(rf)); Field fieldy = rf.getClass().getDeclaredField("y");//暴力反射 fieldy.setAccessible(true); System.out.print(fieldy.get(rf)); ReflectPoint rf2 = new ReflectPoint(2,3); changeStringValue(rf2); System.out.println(rf2); } /* * 反射实现 * 1、普通方法的反射 之 反射实现 str1.charAt(1)的效果 * 2、对接受数组参数的方法的静态反射调用 */ private static void 普通方法的反射(String arg, String str1) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, ClassNotFoundException { Method method = String.class.getMethod("charAt",int.class); System.out.println(method.invoke(str1,1)); System.out.println(method.invoke(str1,new Object[]{2,3})); //正常调用 TestArguments.main(new String[]{"12","33"}); //静态方法调用:编译时不知道调用哪个类的main方法时用 String startClassName = arg; Method methodMain = Class.forName(startClassName).getMethod("main",String[].class); methodMain.invoke(null,new Object[]{new String[]{"111","222"}}); } /** * @throws Exception */ private static void changeStringValue(Object obj) throws Exception { Field[] fields = obj.getClass().getFields(); for (Field field: fields ) { if (field.getType() == String.class) { String oldValue = (String) field.get(obj); String newValue = oldValue.replace('b','a'); field.set(obj,newValue); } } } } class TestArguments { public static void main(String[] args) { for (String str: args) { System.out.println(str); } } }
true true false true false true false true c 23aallaasketaallitcast b 12 33 111 222
反射强大,但是不能用的太多? Bruce Eckel说它不怎么面向对象 。