您的位置:首页 > 职场人生

黑马程序员——学习笔记14.Java反射机制

2014-01-10 23:16 204 查看
----------------------ASP.Net+Android+IOS开发.Net培训、期待与您交流!
----------------------

反射机制

1.反射:反射就是破坏对象的封装特性,把Java类中的各种成分映射成相应的java类。在java中,通过反射可以获取java类中的各个成员,可以操作这个java类的对象中的属性和功能。一个类中的每个成员都可以用相应的反射API类的一个实例对象来表示,通过调用Class类的方法可以得到这些实例对象。或者换个角度来总结:反射就是将一个java类的各成员都封装成对象,通过这些对象来完成各成员的属性和功能-->面向对象的设计思想。这里要学习java.lang.reflect中的相关类以及java.lang.Class类。

2.Class类的基本知识点

(1)基本概念:

Class 类的实例表示正在运行的 Java 应用程序中的类和接口。枚举是一种类,注释是一种接口。每个数组属于被映射为 Class 对象的一个类,所有具有相同元素类型和维数的数组都共享该 Class 对象。基本的 Java 类型(boolean、byte、char、short、int、long、float 和 double)和关键字 void 也表示为 Class 对象。 Class 没有公共构造方法。Class 对象是在加载类时由 Java 虚拟机以及通过调用类加载器中的 defineClass 方法自动构造的。也就是说Class实例就是java类的字节码文件,也就是class文件。Class类描述了哪些方面的信息呢?类的名字,类的访问属性,类所属于的包名,字段名称的列表、方法名称的列表,等等。学习反射,首先就要明白Class这个类。

(2)获取Class实例对象:

方式一:Class c1 = System.class

通过类名.class字节码文件后缀class让编译器辨认是个字节码对象。只要在源程序中出现的类型,都有其对应的Class实例对象。例:int.class ,int[].class(数组类型),void.class。

int.class和Integer.class是不同的字节码文件

System.out.print(int.class == Integer.class) --->false

System.out.print(int.class ==Integer.TYPE)--->true

方式二:Class c2 = new Data().getClass()

通过类已创建的对象来获取这个类的字节码对象(这个类的字节码已经被加载进内存了)。

方式三:Class c3 = Class.forName("java.lang.System")

通过完整的类名来获取这个类的字节码对象

注意:通常较第三中获取方式为常用。Class的forName()方法的作用:若虚拟机中没有这份字节码文件,就需要类加载器加载进内存缓存,然后返回这份字节码文件,若已经加载进了内存,直接返回就可以。

(3)Class类的常用方法:

反射演示:

反射方式获取构造方法对象:

Constructor constructor = String.class.getConstructor(StringBuilder.class);

String str = (String)constructor.newInstrance(new StringBuilder("abc"));

非反射得到的对象:

String str = new String(new StringBuilder("abc"));

获取构造方法对象------>返回Constructor对象

getConstructor(); getDeclaredConstructor()----形参:字节码文件对应的java类构造方法的参数的字节码文件

getConstructors();getDeclaredConstrustosr()-----形参同上,返回Constructor对象数组。

获取字段对象------->返回Field对象

getField();getDeclaredField();-----形参:字节码文件对应的java类的属性名的字符串

getFields();getDeclaredFields();----形参同上,返回Field对象数组。

获取普通方法对象-------->返回Method对象

getMethod();getDeclaredMethod()------形参1:对应方法名的字符串,形参2:字节码文件对应的java类方法参数类型的字节码文件

getMethods();getDeclaredMethods()---形参同上,返回Method对象数组。

例子:Method charAt = Class.forName("java.lang.String").getMethod("charAt", int.class);

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

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

如果传递给Method对象的invoke()方法的第一个参数为null,这有着什么样的意义呢?说明该Method对象对应的是一个静态方法

判断字节码文件的类型

isPrimitive();是否为基本数据类型的字节码文件,有9个属于这一类型。int.class,short.class.....long.class 还有一个是void.class

isArray();是否为数组类型

3.java.lang.reflect包中相关类

(1)Constructor构造方法类,描述的是Class实例对象对应的java类中的构造方法。通过Class类中的newConstructor得到指定构造方法的Constructor对象。Constructor类的主要功能就是能够创建所对应的java类的实例对象,通过newInstance方法创建。

Constructor常用的方法:

newInstance(Object...args):创建这个构造方法对应的对象,传入的参数类型必须和通过反射得到的构造方法对象的参数是同一类型

setAccessible(true)---->此方法设置该构造方法对象的权限;

(2)Field字段类,描述的是Class实例对象对应的java类中的属性(字段).通过Class类中newField方法得到指定属性的Field对象。Field类的主要功能就是能够得到对应的java类的实例对象的属性值。通过Field的get(Object)方法获取,通过传入指定的java类对象,获取的是属性值,若是基本类型的就直接装箱成对应的对象。通过set()方法来修改对应对象上属性值。

Field常用的方法:

get(Object obj);获取指定对象上的属性值

set(Object obj,Object args);修改指定对象上的属性值,用args替代

getType();获取这个字段的Class类型

setAccessible(true);设置访问权限

代码演示1:通过反射方式修改任意一个对象的String类型的属性值,如果属性值内容包含字符a,将a改成b

public static void changeStringField(Object obj) throws IllegalArgumentException, IllegalAccessException{
  //得到这个对象的字节码文件
Class c = obj.getClass();
  //获取这个对象的字段对象数组
Field[] fields = c.getDeclaredFields();
//遍历字段对象数组,找类型是String的字段
for (Field field : fields) {
if(field.getType() == String.class){
  //如果在java类中这个属性不是public,则需要设置权限
field.setAccessible(true);
String oldVal = (String) field.get(obj);
  //将a改成b
String newVal = oldVal.replace("a", "b");
field.set(obj, newVal);
}
}
}

(3)Method一般方法类,描述的是Class实例对象对应的java类中的一般方法。通过Class类中的newField方法得到指定一般方法的Method对象。Method类的主要功能就是能够执行并实现对应的java类的实例对象的对应一般方法的功能。通过Field的invoke(Object obj, Object... args)方法来实现。invoke方法参数对应----> 对带有指定参数的指定对象调用由此 Method 对象表示的底层方法。

Mthiod类的常用方法:

invoke(Object obj, Object...args);

invoke(null,Object...args) 如果obj是null,则执行的这个方法是个静态的方法。不需要指定对象去调用

invoke(Object,obj)如果没有指定的参数,那么这个方法在调用时不需要传入参数

setAccessible(true);

(4)Array数组的反射类。如果两个数组的元素类型和维数相同,那么这个两个数组的字节码文件相同。所有数组的父类都是Object

代码演示2:打印一个对象,如果这个对是个数组就打印出所有元素

public static void printObject(Object obj){
//通过反射方式得到这个对象的字节码文件
Class clazz = obj.getClass();
if (clazz.isArray()) {
//这里用到了java.lang.reflect.Array这个类.这个类中的所有方法都是静态的
int len = Array.getLength(obj);
for (int i = 0; i < len; i++) {
System.out.println(Array.get(obj, i));
}
}else{
System.out.println(obj);
}
}


----------------------ASP.Net+Android+IOS开发.Net培训、期待与您交流!
----------------------

详细请查看:http://edu.csdn.net
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: