Java基础12——反射

来源:互联网 发布:weui.js 编辑:程序博客网 时间:2024/05/01 11:17

------- android培训java培训、期待与您交流! ----------

Java里,类用于描述一类事物的共性,该类事物属性如何,则是由这个类的实例对象确定的,不同对象有不同的属性值。

各个Java类可以用一个类来描述——Class。Class描述类的名称,类的访问属性,类所属的包名,字段名称的列表,方法名称的列表等等。

Class类的各个实例对象代表什么?

对应各个类在内存中的字节码。

一个类被加载器加载到内存中,占用一片存储空间,这个空间里的内容就是类的字节码。

如何得到各字节码对应的实例对象?

类名.class

对象.getClass();

Class.forName("类名");的作用:返回字节码

2种情况:

1.虚拟机已有字节码,直接返回

2.虚拟机未有字节码,则类加载器去加载,把字节码缓存到内存中,并返回字节码

九个预定义Class实例对象

参看Class.isPrimitive方法

int.class == Integer.TYPE

数组类型的Class实例对象

Class.isArray()

反射:就是把Java类中的各种成分映射成相应的java类


Constructor类

Constructor constructor1 = String.class.getConstructor(StringBuffer.class);//选择哪个构造方法

String str2 = (String)constructor1.newInstance(new StringBuffer("abc"));//表示需要传一个StringBuffer对象

注意:

编译时期和执行期的区别!!!

运行期才知道是String,才执行,编译时期不知道,没有执行等号右边的东西,因此要做强制类型转换。

Class.newInstance()方法:

例子:String obj = (String)Class.forName("java.lang.String").newInstance();

该方法内部先得到默认的构造方法,然后用构造方法创建实例对象

该方法内部的具体代码用到了缓存机制来保存默认构造方法的实例对象

反射会使程序性能下降


Field类

fieldX代表的是类上面的成员变量,而不是对象的成员变量。

field.getType() == String.class,不用equals是因为同一份字节码用“==”来判断


Method类代表某个类的一个成员方法

例子:Method methodCharAt = String.class.getMethod("charAt", int.class);

调用方法:

通常方式:System.out.println(str.charAt(1));

反射方式:System.out.println(charAt.invoke(str, 1));

如果给Method对象的invoke()方法的第一个参数为null,意味着该Method对象对应的是一个静态方法

jdk1.5的invoke方法:public Object invoke(Object obj, Object...args)

jdk1.4的invoke方法:public  Object invoke(Object obj, Object[] args)


用反射方法执行某个类的main方法

调用main方法如何为invoke方法传递参数?jdk1.5,整个数组是一个参数,jdk1.4则数组的每个元素对应一个参数,当把一个字符串数组作为参数传递给

invoke方法时,会按jdk1.5语法处理,即把数组打散成为若干个单独的参数,会出现参数类型不对的情况。

解决办法

1. mainMethod.invoke(null, (Object)new String[]("xxx"));

2. mainMethod.invoke(null, new Object[](new String[]("xxx")));


数组的反射

具有相同维数和元素类型的数组属于同一个类型,即具有相同的Class实例对象

代表数组的Class实例对象的getSuperClass()方法返回的父类为Object类对应的Class

基本类型的一维数组可以被当作Object类型使用,不能当作Object[]类型使用:非基本类型的一维数组,既可以当作Object类型使用,又可以当作Object[]类型使用


Arrays.asList()方法处理int[]和String[]的差异


思考:可以得到数组的某个元素类型,不能得到数组类型,因为数组的各个元素可能类型不同。

Object[] a = new Object[]("a", 1);

a[0].getClass().getName();

 

<span style="font-size:12px;">public class ReflectTest {public static void main(String[] args) throws Exception {ReflectPoint pt1 = new ReflectPoint(3, 5);Field fieldY = pt1.getClass().getField("y");// 代表类上的变量,而不是某个对象上的变量System.out.println(fieldY.get(pt1));// 对私有变量进行暴力反射Field fieldX = pt1.getClass().getDeclaredField("x");fieldX.setAccessible(true);System.out.println(fieldX.get(pt1));// 用反射更改成员变量的值changeStringValue(pt1);System.out.println(pt1);// 用反射的方式得到字节码的方法,再用方法作用于某个对象String str1 = "abc";Method methodCharAt = String.class.getMethod("charAt", int.class);System.out.println(methodCharAt.invoke(str1, 1));// 用反射方法调用某个类的main方法// TestArguments.main(new String[]("aaa", "bbb"));// String startingClassName = args[0];// Method mainMethod =// Class.forName(startingClassName).getMethod("main", String[].class);// mainMethod.invoke(null, (Object)new String[]("111", "222", "333"));int[] a1 = new int[] { 1, 2, 3 };String[] a4 = new String[] { "a", "b", "c" };// Array工具类用于完成对数组的反射操作printObject(a1);printObject(a4);printObject("xyz");}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);}}}private static void printObject(Object obj) {Class clazz = obj.getClass();// 是数组则拆分数组元素if (clazz.isArray()) {int len = Array.getLength(obj);for (int i = 0; i < len; i++) {System.out.println(Array.get(obj, i));}} else {System.out.println(obj);}}}</span>



0 0