黑马程序员---反射

------- android培训java培训、期待与您交流! ----------


      引用一位黑马前辈的话说“反射就是把一个Java类中的所有成分映射成相应的Java类”。我们知道Java类用于描述一类事物的共性,该类事物与什么属性,没有什么属性,至于这个属性的值是什么,则是由这个类的实例对象来确定的,不同事物实例对象有不同的属性值。Java程序中的各个Java类,它们是否属于同一类事物,是不是可以用一个类来描述这类事物呢?这个类的名字就是Class,注意与小写class关键字的区别。Class类描述了类的名字、类的访问属性、类所属的包名、字段名称的列表、方法名称的列表等。Class类代表Java类,它的各个实例对象又分别对应各个类在内存中的字节码。

如何得到各个字节码对应的实例对象(Class类型),有3种方法:

1、类名.class,例如,Person.class
2、对象.getClass(),例如,new Date().getClass()
//对象都是由内存中该类的字节码弄出来的
3、Class.forName("类名"),例如,Class.forName("java.util.Date");

Class类中还包含了对其他类型对象的判断方法,如:isArray()--判定此 Class 对象是否表示一个数组类,isInterface()--判定指定的 Class 对象是否表示一个接口类型等等。
九个预定义Class实例对象:八个基本类型和 void。
通过以上3种反射方法得到一个Class对象,调用isPrimitive() 方法来判定指定的 Class 对象是否表示一个基本类型。
(int.class==Interger.TYPE)//true
(int.class==Interger.class)//flase
(int.class.isPrimitive())//true
(int[].class.isPrimitive())//false
我们通反射得到一个类在内存中的字节码对象后,用来做什么呢?表示java类的Class类显然要提供一系列的方法,来获得其中的变量,方法,构造方法,修饰符,包等信息。
Java反射机制的实现要借助于3个类:Constructor,Field,Method;Constructor-类的构造器对象,Field-类的属性对象,Method-类的方法对象。


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

1、得到某个类所有的构造方法:
Constructor[] getConstructors() -- 获得类的所有公共构造函数
Constructor[] getDeclaredConstructors() -- 获得类的所有构造函数(与接入级别无关)

2、得到某一个构造方法:
Constructor getConstructor(Class[] params) -- 获得使用特殊的参数类型的公共构造函数
Constructor getDeclaredConstructor(Class[] params) -- 获得使用特定参数类型的构造函数(与接入级别无关)
//通过区分参数类型与个数来获得构造方法,参数也要用字节码对象表示

3、创建实例对象:
通常方式:String str = new String(new StringBuffer("abc"));
反射方式:String str = (String)constructor.newInstance(new StringBuffer("abc"));
//调用获得的方法时要用到上面相同类型的实例对象
Class.newInstance()方法用到的默认构造函数是通过缓存机制来保存的

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

1、得到某个类所有的字段:
Field[] getFields() -- 获得类的所有公共字段
Field[] getDeclaredFields() -- 获得类声明的所有字段
2、得到某一个字段:
Field getField(String name) -- 获得命名的公共字段
Field getDeclaredField(String name) -- 获得类声明的命名的字段
示例代码:
ReflectPoint point = new ReflectPoint(1,7);

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

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

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

x.setAccessible(true);//暴力反射

System.out.println(x.get(point));
由以上程序可知Field对象是对应到类上面的成员变量而非对象上的成员变量,字段fieldX代表的是x的定义,而不是具体的x变量。
因为变量x是私有的,所以要由getDeclaredField和setAccessible(true)来得到。
思考题:将任意一个对象中的所有String类型的成员变量所对应的字符串内容中的"b"改成"a"。
	public static void changeStr(Object obj) {
		for (Field field : obj.getClass().getDeclaredFields()) {// 获得类声明的所有字段
			if (field.getType() == (String.class)) {
				field.setAccessible(true);// 设置访问权限
				try {
					String oldValue = (String) field.get(obj);
					String newValue = oldValue.replace('b', 'a');
					field.set(obj, newValue);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}
	}
在做题的时候发现了一个很好用的方法field.getModifiers()得到字段前面的修饰符,值是枚举Modifier的对象。

Method类代表某个类中的一个成员方法

1、得到类中的某一个方法:
例子:    
Method charAt = Class.forName("java.lang.String").getMethod("charAt", int.class);
Method getMethod(String name, Class[] params) -- 使用特定的参数类型,获得命名的公共方法
Method getDeclaredMethod(String name, Class[] params) -- 使用特写的参数类型,获得类声明的命名的方法

2、得到类中的所有方法:
Method[] getMethods() -- 获得类的所有公共方法
Method[] getDeclaredMethods() -- 获得类声明的所有方法

3、调用方法:
通常方式:System.out.println(str.charAt(1));
反射方式: System.out.println(charAt.invoke(str, 1)); 
如果传递给Method对象的invoke()方法的第一个参数为null,说明该Method对象对应的是一个静态方法!

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

用反射方式执行某个类中的main方法:

Class.forName(args[0]).getMethod("main", String[].class).invoke(null, (Object)new String[]{"a","b"});
args[0]是通过MyEclipse在调用类里配置好的被调用类的完整类名,这里要注意按jdk1.5的语法,整个数组是一个参数,而按jdk1.4的语法,数组中的每个元素对应一个参数,所以要强转成Object。

数组的反射:

1、具有相同维数和元素类型的数组属于同一个类型,即具有相同的Class实例对象。
(int[].class==int[][].class)//false
(int[].class==String[].class)//false

2、代表数组的Class实例对象的getSuperClass()方法返回的父类为Object类对应的Class。
System.out.println(int[].class.getSuperclass().getName());//结果为java.lang.Object
System.out.println(String[].class.getSuperclass().getName());//结果为java.lang.Object

3、基本类型的一维数组可以被当作Object类型使用,不能当作Object[]类型使用;非基本类型的一维数组,既可以当做Object类型使用,又可以当做Object[]类型使用。
int[] a1 = new int[3];
int[][] a2 = new int[3][4];
String[] b = new String[3];
Object obj1 = a1;
Object obj2 = b;
Object[] obj3 = a1;//编译无法通过
Object[] obj4 = a2;//编译可以通过
Object[] obj5 = b;

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值