---------------------- android培训、java培训、期待与您交流! ----------------------
黑马程序员-反射机制
反射
Java程序中的各个java类属于同一类事物,描述这里类的java类就叫做Class。
Class类代表Java类,它的各个示例对象分别在对应各个类在内存中的字节码。
什么是字节码?
一个类被加载器加载到内存中占有一片存储空间,这个空间里面的内容就说字节码;
不同类的字节码是不同的,所以它们在内存中的内容是不同的,这一个个空间可以分别用故意个个对象来表示,且这些对象具有相同的类型Class类。
如何得到字节码对应的示例对象(Class类型)?
有三种方式:
1.类名.class
如:Person.class;
2.对象.getclass();
如:得到创建该对象的字节码:new Demo().getClass();
3.Class.forName():
如: Class.forName("Java.util.date");返回字节码。
forName()方法先在内存中判断有没有字节码,有就返回,没有就用类加载器加载一个,然后在返回。
java中一共有九个预定义的Class示例对象:
boolean byte char short int long float double 和 void.
使用Class.isprimitive可以判断指定的class对象是不是基本类型。
int.class==Integer.TYPE比较结果为 true 。因为Integer返回的是int数值的字节码。
数组类型的class示例对象,class.isArray();
总之,只要是在源程序中出现的类型,都各自有各自的Class示例对象,如int[],void .
反射是什么呢?
反射 就是把java类中的各种成分映射到相应的java类,如,一个java类中用一个Class类的对象来表示,一个类中的组成部分,成员变量,方法,构造方法。包等信息,也用一个个的java类来表示
java类的class类提供了一些方法来获取其中的变量方法,构造方法,修饰符,包等信息,这些信息用相应类的示例对象来表示,Fild Method Contructor Package。
Constructor类 代表某个类中的构造方法
得到某个类中所有的构造方法
Constructor[] constructors=Class.forName("Java.lang.String").getConstructors();
得到某一个构造方法,获取参数类型为StringBuffer类型的构造方法。
Constructor constructor=Class.forName("Java.lang.String").getConstructor(StringBuffer.Class);
创建实例对象
通常方法:
String str=new String(new StringBuffer("abc"));
反射方法:
String str1=(String) Constructor.newInstance(new StringBuffer("abc"));
再调用获得的构造方法时,要用到上面相同的实例对象,
Class.newInstance()方法
String obj=() Class.forName("Java.lang.String").newInstance();
该方法内部先得到默认的构造方法,然后用构造方法创建实例对象。
该方法内部用到了缓存机制,来保存默认构造方法的示例对象。
Field类 代表某个类的一个成员变量
ReflectPoint pt1=new ReflectPoint(3,5);
//在构造方法中传入3.5
Field fieldY=pt1.getClass().getField("y");
//把要去的变量以字符串的方式传入
//fieldY取出来的不是对象身上的变量,而是类上的,要用它去取某个对象对应的值。
sop(field.get(pt1));
//使用对象的.get(pt1);方法取对象的值。
如果要去的对象变量的值是私有的,那么该怎么办呢,不用担心,java为我们提供了获取私有变量的方法:getDeclaredDield().和setAccessible().
//获取X的值,可以取出私有变量
Field fieldX=pt1.getClass().getDeclaredDield("x");
//获取私有变量的值,有称为暴力反射
fieldX.setAccessible(true);
//打印X值
sop(fieldX.get(pt1));
字段反射
如果要把一个类中的所有String类型的成员变量中的b替换为a怎么实现呢?
public static void changeStringValue(Object obj) Throws Exception
{//将所有的成员变量存入数组
Field[] fields=obj.getClass().getFields();
//对数组进行遍历
for(Field field: fields)
{//使用==比较两个类型的字节码
if(field.getTYPE()==String.class)
{
//取出对象的值
String oldValue=() field.get(obj);
//把旧的值用薪的代替,replace用于替换某一个字符
String newValue=oldValue.replace('b','a');
//将对象的值设置为newValue
field.set(obj.newValue);
}
}
}
在对两个字节码进行比较是否相同时,使用==进行比较,因为有肯能是同一个字节码
Mehhod类 代表某个类中的一个成员方法。
//getMethod参数为一个字符串和一个int.class.
Method methodCharAt=String.class.getMethod("charAt",int.class);
//传入一个字符串对象和要取的位置
sop(methodCharAt.invoke(str1,1);
调用方法:
1.通常方法:
sop(str.charAt());
2.反射方法:
sop(charAt.invoke(str,1);
如果传递给Method对象的invoke方法的第一个参数为 null ,说明该Method对象对应的是一个静态方法、
JDK 1.5与JDK 1.4 invoke方法的区别:
JDK 1.5:使用的是可变参数
public Object invoke(Object obj,Object... args);
JDK 1.4:public Object invoke(Object obj,Object[] args);
在这之前没有可变参数,按 1.4的语法需要将一个数组作为可变参数传递给invoke方法时,数组中的每一个元素分别对应被调用方法的一个参数,所以,调用charAt方法的代码也可以用 1.4改写为charAt。invoke("str",new Object[]{1});