---------------------- 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});