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

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

}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值