---------------------- android培训、java培训、期待与您交流! ----------------------
反射就是把Java类中的各种成分映射成相应的java类。例如,一个Java类中用一个Class类的对象来表示,一个类中的组成部分:成员变量,方法,构造方法,包等等信息也用一个个的Java类来表示,就像汽车是一个类,汽车中的发动机,变速箱等等也是一个个的类。表示java类的Class类显然要提供一系列的方法,来获得其中的变量,方法,构造方法,修饰符,包等信息,这些信息就是用相应类的实例对象来表示,它们是Field、Method、Contructor、Package等等。
反射学习要点
就是学会运用反射的API来获取一个类中各个成员对象,如成员变量、构造方法和普通方法,然后运用获取的对象进行操作。
1、Constructor类
通常我们编写一个类,会写一个构造函数,通过反射如何获取一个类的构造函数呢?Constructor类代表某个类中的一个构造方法
要获取一个类的构造函数,必须先获取该类的实例,这时就用到了Class类,再通过Class类的getConstructor()方法,我们可以这样获取一个Constructor对象
Constructor constructor = Class.forName(“java.lang.String”).getConstructor(StringBuffer.class);
或者这样子
String.class.getConstructor(StringBuffer.class)
获取带两个参数的构造函数
String.class.getConstructor(StringBuffer.class,int.class)
为什么该方法可以接收一个、两个或者多个参数呢?
因为jdk1.5的新特性:可变参数
在jdk1.5之前是用一个数组来实现的
jdk1.4的文档声明如下:
Constructor constructor1 = String.class.getConstructor(StringBuffer.class);
String str2 = (String)constructor1.newInstance("abc");
String str2 = (String)constructor1.newInstance("abc");
Constructor constructor1 = String.class.getConstructor(StringBuffer.class);
String str2 = (String)constructor1.newInstance(new StringBuffer("abc"));
Constructor constructor1 = String.class.getConstructor(StringBuffer.class);
String str2 = (String)constructor1.newInstance("abc"));
System.out.println(str2.charAt(2));
Class.newInstance()方法:
例子:
String obj = (String)Class.forName("java.lang.String").newInstance();
该方法内部先得到默认的构造方法,然后用该构造方法创建实例对象。
该方法内部的具体代码是怎样写的呢?
用到了缓存机制来保存默认构造方法的实例对象。
可以看出反射是比较消耗性能的。
2、Field类
Field类代表某个类中的一个成员变量
使用技巧:eclipse生成构造方法的源代码
在介绍Field类之前,我们先编写一个测试类ReflectPoint
public class ReflectPoint {
private int x;
public int y;
public ReflectPoint(int x, int y) {
super();
this.x = x;
this.y = y;
}
}
然后进行调用一下
ReflectPoint pt1 = new ReflectPoint(3,5);
Field fieldY = pt1.getClass().getField("y");
那fieldYd 值是多少呢?是5吗?
结果不是5!
因为fieldY不是对象身上的变量,而是类上,要用它去取某个对象上对应的值
所以 fieldY不代表具体的值,不是pt1身上的变量Y,而是代表ReflectPoint类上,要用它去取某个对象(不如pt1)System.out.println(fieldY.get(pt1));
既然知道了取值的方式,
用刚才的方法来取一下x的值试试
Field fieldX = pt1.getClass().getField("x");
System.out.println(fieldX.get(pt1));
结果报错了!
Field fieldX = pt1.getClass().getDeclaredField("x");
System.out.println(fieldX.get(pt1));
然后高兴地点击运行,还是不行啊!报错了
Field fieldX = pt1.getClass().getDeclaredField("x");
fieldX.setAccessible(true);
System.out.println(fieldX.get(pt1));
这里有个需求:将任意一个对象中的所有String类型的成员变量所对应的字符串内容中的"b"改成"a"。
我们对之前编写的ReflectPoint类进行扩展,覆盖该类的toString()方法
public class ReflectPoint {
private Date birthday = new Date();
private int x;
public int y;
public String str1 = "ball";
public String str2 = "basketball";
public String str3 = "itcast";
public ReflectPoint(int x, int y) {
super();
this.x = x;
this.y = y;
@Override
public String toString(){
return str1 + ":" + str2 + ":" + str3;}
接着编写功能方法
private static void changeStringValue(Object obj) throws Exception {
Field[] fields = obj.getClass().getFields();//获取目标对象的所有成员对象
for(Field field : fields){//开始遍历
//if(field.getType().equals(String.class)){
if(field.getType() == String.class){//成员变量的类型是否是String
String oldValue = (String)field.get(obj);
String newValue = oldValue.replace('b', 'a');//a代替b
field.set(obj, newValue);//将值设置进目标对象里面
}
}
ReflectPoint pt1 = new ReflectPoint(3,5);
changeStringValue(pt1);
System.out.println(pt1);
3、Method类
str1.chatAt();
str2.charAt();
Method methodCharAt = String.class.getMethod("charAt", int.class);
System.out.println(methodCharAt.invoke(str1, 1));
System.out.println(methodCharAt.invoke(null, 1));
dk1.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})形式。
1.4的调用形式
System.out.println(methodCharAt.invoke(str1, new Object[]{2}));
4、用反射执行某个类的main()方法
TestArguments.main(new String[] {"111","222","333"});
按照上面的知识点我们用反射的方式继续努力调用mian()方法
String startingMethodClassName=args[0];
Method mainMethod=Class.forName(startingMethodClassName.getMethod("main"),String[].class);
mainMethod.invoke(null,new String[]{"111","222","333"});
mainMethod.invoke(null,new Object[]{new String[]{"111","222","333"}});
mainMethod.invoke(null,(Object)new String[]{"111","222","333"});
我们先来看看下面的代码
int [] a1 = new int[3];
int [] a2 = new int[4];
int[][] a3 = new int[2][3];
String [] a4 = new String[3];
System.out.println(a1.getClass() == a2.getClass());
System.out.println(a1.getClass() == a4.getClass());
System.out.println(a1.getClass() == a3.getClass());
System.out.println(a1.getClass().getSuperclass().getName());
System.out.println(a4.getClass().getSuperclass().getName());
结果发现都是java.lang.Object
小总结
1)具有相同维数和元素类型的数组属于同一个类型,即具有相同的Class实例对象。
2)代表数组的Class实例对象的getSuperClass()方法返回的父类为Object类对应的Class。
3)基本类型的一维数组可以被当作Object类型使用,不能当作Object[]类型使用;非基本类型的一维数组,既可以当做Object类型使用,又可以当做Object[]类型使用。
分析一下下面的代码
Object aObj1 = a1;
Object aObj2 = a4;
Object[] aObj3 = a1;
Object[] aObj4 = a3;
Object[] aObj5 = a4;
Array工具类用于完成对数组的反射操作
private static void printObject(Object obj) {
Class clazz = obj.getClass();//获取参数的字节码
if(clazz.isArray()){//判断是否是数组
int len = Array.getLength(obj);//得到数组的长度
for(int i=0;i<len;i++){
System.out.println(Array.get(obj, i));//打印数组
}
}else{
System.out.println(obj);//不是数组正常打印
}
}
反射实现框架
框架与框架要解决的核心问题
我做房子卖给用户住,由用户自己安装门窗和空调,我做的房子就是框架,用户需要使用我的框架,把门窗插入进我提供的框架中。框架与工具类有区别,工具类被用户的类调用,而框架则是调用用户提供的类。
框架要解决的核心问题
我在写框架(房子)时,你这个用户可能还在上小学,还不会写程序呢?我写的框架程序怎样能调用到你以后写的类(门窗)呢?
因为在写才程序时无法知道要被调用的类名,所以,在程序中无法直接new 某个类的实例对象了,而要用反射方式来做。
Collection collections = new HashSet();
ReflectPoint pt1 = new ReflectPoint(3,3);
ReflectPoint pt2 = new ReflectPoint(5,5);
ReflectPoint pt3 = new ReflectPoint(3,3);
collections.add(pt1);
collections.add(pt2);
collections.add(pt3);
collections.add(pt1);
System.out.println(collections.size());
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + x;
result = prime * result + y;
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
final ReflectPoint other = (ReflectPoint) obj;
if (x != other.x)
return false;
if (y != other.y)
return false;
return true;
}
InputStream ips = ReflectTest2.class.getResourceAsStream("/cn/itcast/day1/resources/config.properties");
Properties props = new Properties();
props.load(ips);//读取配置文件
ips.close();
String className = props.getProperty("className");
//通过反射的方式得到Collection
//这里的newInstance()调用的是无参数的构造方法
Collection collections = (Collection)Class.forName(className).newInstance();
ReflectPoint pt1 = new ReflectPoint(3,3);
ReflectPoint pt2 = new ReflectPoint(5,5);
ReflectPoint pt3 = new ReflectPoint(3,3);
collections.add(pt1);
collections.add(pt2);
collections.add(pt3);
collections.add(pt1);
System.out.println(collections.size());
InputStream ips = ReflectTest2.class.getResourceAsStream("/cn/itcast/day1/resources/config.properties");
---------------------- android培训、java培训、期待与您交流! ----------------------