黑马程序员——Java高新技术之反射

来源:互联网 发布:ubuntu 安装坚果云 编辑:程序博客网 时间:2024/04/28 13:03
------- android培训、java培训、期待与您交流! ----------

一、概述

反射就是把Java类中的各种成分映射成相应的java类。例如,一个Java类中用一个Class类的对象来表示,一个类中的组成部分:成员变量,方法,构造方法,包等等信息也用一个个的Java类来表示,就像汽车是一个类,汽车中的发动机,变速箱等等也是一个个的类。表示java类的Class类显然要提供一系列的方法,来获得其中的变量,方法,构造方法,修饰符,包等信息,这些信息就是用相应类的实例对象来表示,它们是Field、Method、Contructor、Package等等。

一个类中的每个成员都可以用相应的反射API类的一个实例对象来表示,通过调用Class类的方法可以得到这些实例对象后,得到这些实例对象后有什么用呢?怎么用呢?这正是学习和应用反射的要点。

二、Constructor类

Constructor类代表某个类中的一个构造方法

得到某个类所有的构造方法:

例子:Constructor [] constructors=Class.forName("java.lang.String").getConstructors();

得到某一个构造方法:

例子:   ConstructorMethod类代表某个类中的一个成员方法

得到类中的某一个方法:

例子:       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对象对应的是一个静态方法!

jdk1.4和jdk1.5的invoke方法的区别:

Jdk1.5:public Objectinvoke(Object obj,Object... args)

Jdk1.4:public Objectinvoke(Object obj,Object[] args),即按jdk1.4的语法,需要将一个数组作为参数传递给invoke方法时,数组中的每个元素分别对应被调用方法中的一个参数,所以,调用charAt方法的代码也可以用Jdk1.4改写为 charAt.invoke(“str”, new Object[]{1})形式。constructor = Class.forName(“java.lang.String”).getConstructor(StringBuffer.class);

创建实例对象:

通常方式:String str = new String(new StringBuffer("abc"));

反射方式: String str = (String)constructor.newInstance(newStringBuffer("abc"));

         //调用获得的方法时要用到上面相同类型的实例对象

Class.newInstance()方法:

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

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

该方法内部的具体代码是怎样写的呢?用到了缓存机制来保存默认构造方法的实例对象。

三、Field类

Field类代表某个类中的一个成员变量

演示用eclipse自动生成Java类的构造方法

问题:得到的Field对象是对应到类上面的成员变量,还是对应到对象上的成员变量?类只有一个,而该类的实例对象有多个,如果是与对象关联,哪关联的是哪个对象呢?所以字段fieldX 代表的是x的定义,而不是具体的x变量。

示例代码:

         ReflectPoint point = newReflectPoint(1,7);

         Field y = Class.forName("cn.itcast.corejava.ReflectPoint").getField("y");

         System.out.println(y.get(point));

         //Field x =Class.forName("cn.itcast.corejava.ReflectPoint").getField("x");

         Field x =Class.forName("cn.itcast.corejava.ReflectPoint").getDeclaredField("x");

         x.setAccessible(true);

         System.out.println(x.get(point));

四、Method类

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对象对应的是一个静态方法!

jdk1.4和jdk1.5的invoke方法的区别:

Jdk1.5:public Objectinvoke(Object obj,Object... args)

Jdk1.4:public Objectinvoke(Object obj,Object[] args),即按jdk1.4的语法,需要将一个数组作为参数传递给invoke方法时,数组中的每个元素分别对应被调用方法中的一个参数,所以,调用charAt方法的代码也可以用Jdk1.4改写为 charAt.invoke(“str”, new Object[]{1})形式。

代码实践如下:

 

/** *  */package com.bq2015;import java.lang.reflect.Constructor;import java.lang.reflect.Field;/** * @author Kylin * */public class ReflactTest {public ReflactTest(int i, int j) {// TODO Auto-generated constructor stub}public static void changeStringValue(Object obj) throws Exception{//从字节码文件中获取所有成员变量字段Field[] fields = obj.getClass().getFields();//迭代所有变量for(Field field : fields){//if(field.getType().equals(String.class)){//获取各类型字段并对比String类字节码文件if(field.getType() == String.class){//通过get方法获取并将Field类向下转型成String类String oldValue = (String)field.get(obj);//将字段中的所有b字符替换成a字符String newValue = oldValue.replace('b','a');//替换后需要将newValue设置field.set(obj, newValue);}}}public static void main(String[] args) throws Exception, NoSuchMethodException {//第一种构造方法,参数类型为StringBuffer//new String(new StringBuffer("abc"));/* * 第二种方法用反射技术构造: *  *///创建一个StringBuffer类的构造函数,是通过字符码文件类中的getConstructor方法获取的Constructor<String> constructor1 = String.class.getConstructor(StringBuffer.class);//通过String变量str2接收用constructor1对象中的newInstance方法构造的StringBuffer类数据String str2 = constructor1.newInstance(new StringBuffer("abc"));//输出第二位字符,验证是否构造成功。System.out.println(str2.charAt(1));//创建ReflectPoint对象ReflectPoint pt1 = new ReflectPoint(3,5);//获取pt1字节码文件中的成员变量y是它所对应的字段。这里fieldY的值 不是5.是用它去获取某对象上的值。Field fieldY = pt1.getClass().getField("y");//获取y中的值,并输出System.out.println(fieldY.get(pt1));/* * 暴力访问 * *///Declared申明过的,只要是申明过的都可以通过getDeclaredField访问。Field fieldX = pt1.getClass().getDeclaredField("x");//设置可以访问fieldX.setAccessible(true);//用fileld类中get方法输出(可以想象成某字段中迭代方法取一小部分)。System.out.println(fieldX.get(pt1));//改变值方法展示System.out.println("替换前:"+pt1);changeStringValue(pt1);System.out.println("替换前:"+pt1);}}

0 0
原创粉丝点击