反射的笔记

  • 格式:docx
  • 大小:124.71 KB
  • 文档页数:10

1. 反射的笔记(2016-04-16) 1.1. 反射是什么 1.1.1. Class,代表的是什么? 他是描述各种java类。 反射就是把Java类中的各种成分反射成相应的java类。 例如:Method、Field、Construtor、Package...等 Class claz1 = 字节码 就是把字节码从硬盘中加载到内存中,每一份字节码文件就是一个Class对象。

1.1.2. 三种获取Class对象的方法:

例如:People peole = new People(); Class claz1 = people.getClass() Class claz2 = People.class Class claz3 = Class.forName(“People类的权限定名”)

1.1.3. Class.forName()的作用

得到这个类的字节码文件,有两种情况。一、需要加载的字节码文件已经加载进来了,不需要再加载,直接找到这个字节码文件返回。二、虚拟机在内存中没有找到这个字节码的文件,然后,用类加载器去加载到内存,返回。 注:在连接数据库的时候,需要加载一个数据库驱动包,使用的就是Class.forName()加载驱动包,防止重复加载。

1.1.3.1. 九个预定义的Class实例对象 四型八种和一个void是基本的类型 int.class.isPrimitive()//true Int.class == Integer.TYPE;//Integer是int 的包装类型。

1.2. 构造方法的反射 Constructor cons = String.class.getConstructor(StringBuffer.class);//指定获取哪一个构造函数 String str = (String)cons.newInstance(new StringBuffer(“abc”);//需要传递响应的构造函数的参数

1.2.1. 为什么在这里需要强转?

程序开发分为编译时和运行时,编译时严格按照java语法进行检验,翻译成二进制文件,不会去执行等号右边的表达式,即编译阶段不做运算。运行时才会去执行知道这个创建一个 String的对象。

1.2.2. 无参构造的便捷创建

Clazz.newInstance()//可以快速创建一个对象。不需要获取Contructor对象,然后子啊创建。 但这个方法底层也是先创建Constructor然后再创建。

1.3. 成员变量的反射: ReflectField rf = new ReflectField(3, 5); 1.3.1. //私有字段的反射1 Field fieldY = rf.getClass().getField("y"); System.out.println(fieldY.get(rf));

使用getField()得不到私有字段。 1.3.2. //私有字段的反射

Field fieldY = rf.getClass().getDeclaredField("y"); System.out.println(fieldY.get(rf));

虽然能够得到私有字段fieldY ,但是对象rf不能访问私有字段。 1.3.3. //私有字段的反射 Field fieldY = rf.getClass().getDeclaredField("y"); //暴力破解 fieldY.setAccessible(true); System.out.println(fieldY.get(rf)); 加上这段代码就能对象就有访问该私有字段的权利了。

1.3.4. 小练习:你给我一个对象,我就能把对象中的String字段的值进行修

改。框架 @Test public void testFieldChange()throws Exception{ ReflectField rf = new ReflectField(3,5); changeStringValues(rf); System.out.println(rf); }

private void changeStringValues(ReflectField rf) throws Exception{ Field[] fields = rf.getClass().getFields();

for(Field field : fields){ if(field.getType() == String.class){//健壮性判断。使用==比使用equals()更好,因为String的Class对象只有一份

String oldValue = (String) field.get(rf); String newValue = oldValue.replace("b", "a"); field.set(rf, newValue);//修改对象的值 } } }

1.4. 利用反射的方法调用String 类的charAt()方法

public class ReflectMethod { public static void main(String[] args) throws Exception { String str = "abc"; Method method = str.getClass().getMethod("charAt", int.class); System.out.println(method.invoke(str, 1));//方法这个对象调用他的方法,传递当前这个方法属于哪个对象,传递方法的参数。 } }

1.4.1. 理解面向对象的思维方式:

例如,人在黑板上画圆,有三个对象人、黑板、圆,那么画圆这个方法定义在哪个类里面哪? 定义在圆这个类里面。因为画圆涉及到圆心半径这些属性,这些属性都是圆的属性,所以这个画圆的方法定义在圆中。人只是调用这个方法去画圆。 还有,人关门。列车司机刹车等。 总结:专家模式,谁拥有数据,谁就是干这事的数据专家。

1.4.2. 区分jdk1.4和jdk1.5的一个小区别

1.4,之前,传递不固定的参数的时候都是用的Object数组来接收,1.5之后,都是用可变参来接收。明显使用可变参来接收要方便一些。要明白为什么方便。

1.4.3. 静态方法的调用 在调用方法是不需要传递对象,写成null即可,因为静态方法调用不需要对象就可以了。Method.invoke(null,””); 1.5. 对接收数组参数的成员方法的调用

String className= args[0];//传过来的类 的全限定名。 Method mainMethod = Class.forName(className).getMethod("main",String[].class); mainMethod.invoke(null, new Object[]{new String[]{"11","22","33"}}); //mainMethod.invoke(null, (Object)new String[]{"11","22","33"} ); } }

class TestMethodArrayArgument{ public static void main(String[] args) { for(String str : args){ System.out.println(str); } } } 在编译这个方法时,需要传递TestMethodArrayArgument这个类的全限定名作为参数。

1.5.1. 为什么需要用反射的方式调用方法?为什么不直接调用这个类的这

个方法? 因为,有时候我们并不知道这个类的类名,你可以通过参数传递给我,或者通过读取配置参数的方式,读取到这个累的全限定名,然后通过反射,调用这个类的方法。 1.6. 数组与Object的关系及其反射类型

int[] a1 = new int[]{1,2,3}; int[] a2 = new int[4]; int[][] a3 = new int[3][4]; String[] a4 = new String[]{"sdf","dfs","dsf"};

System.out.println(a1.getClass() == a2.getClass());//true // System.out.println(a1.getClass() == a3.getClass());编译不通过 // System.out.println(a1.getClass() == a4.getClass());编译不通过 System.out.println(a1.getClass().getSuperclass() == a4.getClass().getSuperclass());//true System.out.println(a1.getClass().getSuperclass());//class java.lang.Object System.out.println(a4.getClass().getSuperclass());//class java.lang.Object

Object aObj = a1; Object bObj = a2; Object cObj = a3; Object dObj = a4; //Object[] obj = a1;//报错,不能把一个int类型的数组指向object数组 Object[] obj = {1,2,3}; Object[] eObj = a3;//eObj数组的成员是一维数组 Object [] fObj = a4;//fObj数组中的成员是String对象 System.out.println(eObj.length);//3

System.out.println(a1);//[I@c17164 System.out.println(a4);//[Ljava.lang.String;@1fb8ee3

System.out.println(Arrays.asList(a1));//[[I@c17164] System.out.println(Arrays.asList(a4));//[sdf, dfs, dsf] 分析: 一维数组的父类和二维数组的父类都是Object. 一维数组的类型都是相同的。 List Arrays.asList(Object[] )jdk1.4 List Arrays.asList(T... t) jdk1.5 当前使用的1.5,但向下兼容。当你传一个String数组时,他会进项一个判断使用jdk1.4 当你传一个int数组,他会使用jdk1.5,把这个数组当成一个对象,把这个数组对象转化成list的一个对象,而不是把数组的成员转成list的对象。