反射:就是把Java类中的各种成分映射成相应的Java类,通过这种能力可以彻底了解自身的情况为下一步动作做准备。
Java的反射机制实现主要是借助:Class(类对象),Construct(类的构造器对象),Field(属性字段对象),Method (类的方法对象)四个类。
Class:Java中用Java类来描述同一类的事物,描述这一类事物的Java类名就是Class。
如何知道Java类是否属于的同一类事物就可以通过Class类中的方法
由于Class类中没有构造函数,因此不能使用new Class()这种形式来创建Class类对象。
实例化Class类的方式有点特殊,实例化Class类得到得是字节码的形式,得到字节码的三种方式:
1.对象.getClass();new Date().getClass()//得到创建Date对象的字节码
2.类.class;//System.class//得到某个类的字节码
3.forName();//Class.forName("java.util.Date");得到Date类的字节码。
除了类.class获取字节码Java中还有8个基本类型boolean
、byte
、char
、short
、int
、long
、float
和 double
和关键字 void
也表示为 Class
对象。
package com.leo.blog;
public class ClassDemo {
public static void main(String[] args) {
String str = "abc";
Class cls = str.getClass();
Class cls1 = String.class;
Class cls2 = null;
try {
cls2 = Class.forName("java.lang.String");
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//查看结果三个实例化对象是否是属于同一份字节码
System.out.println(cls==cls1);//true
System.out.println(cls==cls2);//true
//检查是一个基本类型字节码
System.out.println(cls.isPrimitive());//false
System.out.println(int.class.isPrimitive());//true
System.out.println(int.class==Integer.class);//false
System.out.println(int.class==Integer.TYPE);//true
}
}
只要是在源程序中出现的类型,都具有各自的Class实例对象,由于使用forName的方式,会抛出ClassNotFoundException异常,是为了避免找不到类名。
Construct类
通过反射得到String类型中的构造方法获得字符串中的某个字符。
package com.leo.blog;
import java.lang.reflect.*;
public class ReflectConstructDemo {
public static void main(String[] args) {
//创建一个Construct类型对象
Constructor cons = null;
try {
cons = String.class.getConstructor(StringBuffer.class);
String str = (String)cons.newInstance(new StringBuffer("LEO"));
System.out.println(str.charAt(2));//得到第三个字符:0
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
注:在获得方法跟调用方法时所用到的实例类需要相同。
Field:通过反射修改类中的属性。
package com.leo.blog;
public class ReflectPoint {
private int x;
public int y;
public String str1 = "ball";
public String str2 = "basketball";
public String str3 = "LeoBall";
public ReflectPoint(int x, int y) {
super();
this.x = x;
this.y = y;
}
@Override
public String toString() {
return "ReflectPoint [str1=" + str1 + ", str2=" + str2 + ", str3="
+ str3 + "]";
}
}
先创建一个类,利用反射机制对类中的属性进行修改。
package com.leo.blog;
import java.lang.reflect.Field;
public class ReflectDemo {
/**
* @param args
*/
public static void main(String[] args) throws Exception{
// TODO Auto-generated method stub
ReflectPoint rp = new ReflectPoint(3,5);
Field fdY =rp.getClass().getField("y");
System.out.println(fdY.get(rp));
Field fdX =rp.getClass().getDeclaredField("x");
fdX.setAccessible(true);
System.out.println(fdX.get(rp));
System.out.println(rp);
changeStrValue(rp);
System.out.println(rp);
}
public static void changeStrValue(Object obj) throws Exception
{
//获取对象所有字段
Field[] fds = obj.getClass().getFields();
for (Field fd:fds) {//遍历对象中的所有字段
//同一份字节码的比较使用==号
if(fd.getType()==String.class){//比较是否是字符串类型字段
String oldVal = (String)fd.get(obj);//获取对象的字段的值
String newVal = oldVal.replace('b','a');//替换字段值中b为a
fd.set(obj, newVal);//设置对象中字段值
}
}
}
}
getDeclaredFields方法可以获取全部的属性包括私有的,getDeclaredField获取的是类中的单个属性,getField跟getFields只能是获取公共的属性。而通过setAccessible可以强制的对私有属性进行修改。
Method类:通过反射得到一个方法。
package com.leo.blog;
import java.lang.reflect.Method;
class MethodPerson
{
public void play(String str)
{
System.out.print(str);
}
public static void play(int times)
{
System.out.print("玩"+times+"局");
}
}
public class ReflectMethod {
/**
* @param args
*/
public static void main(String[] args)throws Exception {
// TODO Auto-generated method stub
MethodPerson mp = new MethodPerson();
Class c = mp.getClass();
//创建Method类对象,通过getMethod方法传入方法名,和参数类型
Method me = c.getMethod("play", int.class);
//使用invoke去调用类中的paly参数为int类型的方法,
me.invoke(null, 10);
Method me1 = c.getMethod("play", String.class);
//使用invoke去调用类中的paly参数为String类型的方法,
me1.invoke(mp, "BASKETBALL");
}
}
执行结果就会是:玩10局BASKETBALL