深入理解反射

来源:互联网 发布:c 并发编程指南 pdf 编辑:程序博客网 时间:2024/06/06 10:58
众所周知,如果没有了java的反射,那么java中的框架将不复存在,所以当我们学好了反射以后对我们日后学习框架是有很多的帮助的,下面,我把我学反射的一些总结分享给大家。

刚接触反射的时候感觉它真是太帅了,尤其是暴力反射我感觉真的很牛x(下面我会介绍的),其实反射说白了点讲,就是通过java中给我们提供的一些类和方法,将我们类的字段、方法以及各种成分映射成相应的它们给我们提供的类和方法。

Class类为反射的基石,下面我将介绍三种方式获得Class对象的方式:


//以String类为例,获得其字节码对象,首先我们定义一个String对象String str = "getClass";//第一种方式Class stringClassOne = str.getClass();//第二种方式Class stringClassTwo = String.class;//第三种方式,forName()方法的参数必须是包名和类名Class stringClassThree = Class.forName("java.lang.String");//但是,当我们通过上面的方式获得了字节码对象以后,我们可以怎么用这个对象呢?String str = "reflect";//这个方法判断当前的类型是否为原始类型System.out.println(str.getClass().isPrimitive());//我们可以看出Integer和int的字节码文件并不是同一份,但是Integer.Type得到的是原始类型的字节码文件System.out.println(Integer.class == int.class);System.out.println(Integer.TYPE == int.class);//通过Class对象看是否为一个数组类型System.out.println(new int[2].getClass().isArray());//通过Class对象得到当前对象的类型System.out.println("The class of " + str +" is " + str.getClass().getName());//但是上面的getName()这个方法有几点我们应该注意//首先,如果此类对象表示一个基本类型或 void,则返回的名字是一个与该基本类型或 void所对应的 Java语言关键字相同的 String。 System.out.println(int.class.getName());System.out.println(void.class.getName());/* * 如果此类对象表示一个数组类,则名字的内部形式为:表示该数组嵌套深度的一个或多个 '[' 字符加元素类型名。元素类型名的编码如下: *   元素类型名     编码boolean      Zbyte      Bchar      Cclass or interface  Lclassname;double      Dfloat      Fint     Ilong     Jshort     S  */System.out.println(new Object[3].getClass().getName());System.out.println(new int[3][4][5][6][7][8][9].getClass().getName());//下面,我们可以通过Class的实例对象创建一个对应的类的实例对象:@SuppressWarnings("unchecked")//得到String类型的Class对象Class<String> stringClass = (Class<String>)Class.forName("java.lang.String");//通过这个Class对象得到一个构造方法,但是构造方法参数类型并不相同,所以我们给这个方法一个参数Constructor<String> con = stringClass.getConstructor(char[].class);//用这个构造方法创建一个String类型的实例,参数要与上面给的参数类型相对应String newValue = con.newInstance(new char[]{'j','a','v','a'});System.out.println(newValue);//我们也可以通过Class的实例对象创建一个String类型的实例//这种方法是用缓存一个无参数的构造方法实现的,所以,由此看出,反射是比较消耗性能的String str = stringClass.newInstance();System.out.println(str.length());

下面我们得到对象身上的字段:

public class ClassTest {public static void main(String[] args) throws Exception {Point point = new Point(13,14,"javareflect","man");@SuppressWarnings("unchecked")Class<Point> pointClass = (Class<Point>) Class.forName("com.java.day01.ClassTest$Point");//因为y字段是public的,所以我们可以通过这种方式访问Field yField = pointClass.getField("y");int y = (Integer) yField.get(point);System.out.println(y);//通过下面的这种方式访问私有的字段Field xField = pointClass.getDeclaredField("x");xField.setAccessible(true);int x = (Integer) xField.get(point);System.out.println(x);//我们也可以将其私有的字段更改,通过上面这种反射的方式,是不是很帅气!!!System.out.println(point);Field[] fields = pointClass.getDeclaredFields();for(Field field : fields) {if(field.getType() == String.class) {field.setAccessible(true);field.set(point, field.get(point).toString().replace('a', '$'));}}System.out.println(point);}static class Point {private int x;public int y;private String name;private String sex;public Point(int x, int y, String name, String sex) {super();this.x = x;this.y = y;this.name = name;this.sex = sex;}@Overridepublic String toString() {return "Point [name=" + name + ", sex=" + sex + "]";}}}

下面我们得到对象身上的方法:

String str = "javareflect";Class<String> strClass = (Class<String>) str.getClass();//通过Class实例得到String对象的方法Method method = strClass.getMethod("charAt", int.class);//方法与对象是没有关系的,它是属于类的,是方法作用在某个对象身上char printVal = (Character)method.invoke(str, 2);System.out.println(printVal);深入理解关于方法的反射public class ClassTest {public static void main(String[] args) throws Exception {//我们通过run配置,给主方法的数组赋值,从而得到其他类的类名,然后运行这个类的主函数String className = args[0];Method mainMethod = Class.forName(className).getMethod("main", String[].class);/* * 由于jdk1.5之前并没有可变参数这一特性,以前invoke的第二个参数是一个Object数组类型,而高的jdk版本 * 必须向下兼容,所以当我们new一个引用类型的数组时,java会把他认为是一个Object类型的数组,从而导致程序 * 出错,所以我们自己new一个Object数组将正确的参数类型给放进去,这样程序就不会出错了,但是基本类型并没有继承 * Object类型,所以基本类型的数组并不存在这样的问题。 */mainMethod.invoke(null, new Object[] {new String[] {"hxl","znb"}});Method m1 = Class.forName(className).getMethod("say",char[].class);m1.invoke(null, new char[] {12});}}class TestMain {public static void main(String[] args) {for(String arg : args) {System.out.println(arg);}}public static void say(char[] i) {System.out.println("i am primitive type test");}}

关于数组的反射:

public class ClassTest {public static void main(String[] args) throws Exception {//利用Array类实现数组的反射Object obj = new int[] {12,14};//将obj这个不知道的类型打印输出if(obj.getClass().isArray()) {int length = Array.getLength(obj);for(int i = 0;i < length;i++) {Object arrVal = Array.get(obj, i);System.out.println(arrVal);}} else {System.out.println(obj);}}}

0 0
原创粉丝点击