定义
在运行状态中,对于任意一个类,都能够知道这个类中的所有属性和方法(任何权限);对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
反射机制的作用:
- 在运行中分析类的能力
- 在运行中查看对象
- 实现通用的数组代码
Class类
获取CLass实例:
- Object类中的getClass方法会返回一个Class类型的实例
例如:Class cl =user.getClass()
getName方法:返回类的名字,例如下面的语句:
cl.getName();
输出的是:com.sendi.entity.User
2.forName(String)方法:获得类名对应的CLass对象,例如
String className="com.sendi.entity.User";
Class cl=Class.forName(className);
3.T.class:
Class cl1=int.class;
Class cl2=double.class;
4.创建对象
newInstance()方法:可以方便快捷地创建一个对象出来,例如:
User user3=u.getClass().newInstance();
如果构造器有参数,则需要使用Constructor类中的newInstance方法。
getFields方法:返回Field数组
getMethods方法:返回Method数组
getConstructors方法:返回Constructor数组
getDeclareFields方法:返回类中声明的全部域
getDeclareMethods方法:返回类中声明的全部方法
getDeclareConstructors方法:返回Constructor
setAccessible(true);//设置访问权限
其中包括私有的和受保护的成员,但不包括超类。
利用反射分析类的能力
在java.lang.reflex包中有三个类:Field、Method和Constructor,他们分别用于描述类的域、方法、构造器。他们都有一个getName的方法,用来返回项目的名称。
- Field类:
提供public域
getModifiers():返回一个整形数值,可供Modifiers.toString方法分析出修饰符 - Method类:
提供方法
getModifiers():返回一个整形数值,可供Modifiers.toString方法分析出修饰符
Class getReturnType():返回方法返回的类型 - Constructor类:
提供构造器
getModifiers():返回一个整形数值,可供Modifiers.toString方法分析出修饰符
Class getDeclaringClass():返回一个描述类中定义的构造器、方法或域的Class对象。
Class[] getParameterTypes():返回描述构造器参数类型数组。
例子,分析类中的所有成员:
public class Demo2 {
/**
* @param args
*/
public static void main(String[] args) {
String name;
if(args.length>0)name=args[0];
else{
Scanner in=new Scanner(System.in);
System.out.println("enter class name(e.g.java.util.Date)");
name=in.next();
}
try {
Class cl=Class.forName(name);
Class superCl=cl.getSuperclass();
String modifiers=Modifier.toString(cl.getModifiers());
if(modifiers.length()>0)System.out.print(modifiers+" ");
System.out.print("class "+name);
if (superCl!=null && superCl!=Object.class)
System.out.print(" extends "+superCl.getName());
System.out.print("\n{\n");
printConstuctors(cl);
System.out.println();
printMethods(cl);
System.out.println();
printFields(cl);
System.out.println("}");
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
System.exit(0);
}
private static void printFields(Class cl) {
// TODO Auto-generated method stub
Field[] fields=cl.getDeclaredFields();
for (Field field : fields) {
Class type=field.getType();
String name=field.getName();
System.out.print(" ");
String modifiers=Modifier.toString(field.getModifiers());
if(modifiers.length()>0)System.out.print(modifiers+" ");
System.out.println(type.getName()+" "+name+";");
}
}
/**
* 打印方法
* @param cl
*/
private static void printMethods(Class cl) {
// TODO Auto-generated method stub
Method[] methods=cl.getMethods();
for (Method method : methods) {
Class retType=method.getReturnType();
String name=method.getName();
System.out.print(" ");
String modifiers=Modifier.toString(method.getModifiers());
if(modifiers.length()>0)System.out.print(modifiers+" ");
System.out.print(retType.getName()+" "+name+"(");
Class[] paramType=method.getParameterTypes();
for(int i=0;i<paramType.length;i++){
if(i>0)System.out.print(", ");
System.out.print(paramType[i].getName());
}
System.out.println(");");
}
}
/**
* 打印构造方法
* @param cl
*/
private static void printConstuctors(Class cl) {
// TODO Auto-generated method stub
Constructor[] constructors=cl.getConstructors();
for (Constructor constructor : constructors) {
String name=constructor.getName();
System.out.print(" ");
String modifiers=Modifier.toString(constructor.getModifiers());
if(modifiers.length()>0)System.out.print(modifiers+" ");
System.out.print(name+"(");
//参数
Class[] paramTypes=constructor.getParameterTypes();
for(int i=0;i<paramTypes.length;i++){
if(i>0)System.out.print(", ");
System.out.print(paramTypes[i].getName());
}
System.out.println(")");
}
}
}
动态代理的应用
##主题接口
interface Suject {
fun request()
}
##真正的主题
class RealSubject : Suject {
override fun request() {
println("real subject")
}
}
##InvocationHandler
class ProxyHandler(val subject: Suject) : InvocationHandler {
override fun invoke(proxy: Any?, method: Method?, args: Array<out Any>?): Any? {
println("before-------------")
println("call fun: ${method?.name}")
val obj = method?.invoke(subject)//调用真正主题的方法
println("after-------------")
return obj
}
}
##使用
fun main(args: Array<String>) {
//创建目标对象
val realSubject = RealSubject()
//创建调用处理器
val handler = ProxyHandler(realSubject)
//动态生成代理对象
val proxySubject = Proxy.newProxyInstance(RealSubject::class.java.classLoader,
RealSubject::class.java.interfaces,
handler) as Suject
proxySubject.request()
}
打印结果:
before-------------
call fun: request
real subject
after-------------
小总结
在动态代理实现中,无需编写代理类,而是在运行时生成一个代理类,并且调用对应方法的时候可以添加其他的逻辑,使程序更灵活。
在运行时使用反射
Field类中的get方法:获取该域的当前值,例如:
User user=new User("asendi",11);
Class cl=user.getClass();
Field f01=cl.getDeclaredField("name");//name域
f01.setAccessible(true);//设置访问权限
Object obj=f01.get(user);
System.out.println(obj.toString());
打印结果是:asendi
注意: 当name是私有时,则必须加f01.setAccessible(true)来设置访问权限。
Field类中的set方法:用来设置当前域的值,例如:
Field f02=cl.getDeclaredField("age");//age域
f02.setAccessible(true);
Integer age=f02.getInt(user);
System.out.println("before:"+age);
f02.set(user, 22);
Integer age2=f02.getInt(user);
System.out.println("after:"+age2);
输出结果是:
before:11
after:22
java.lang.reflect.Array
Object get(Object array,int index):返回指定数组对象中索引的值。
void set(Object array,int index):给指定数组对象中索引的对象指定新值。
int getLength(Object array):返回指定数组的长度。
Object newInstance(Class componentType,int length):返回一个具有给定类型,给定长度的新数组。
Object newInstance(Class componentType,int… length):创建具有指定组件类型和维度的新数组。
下面给出一个数组拷贝的方法:
public static Object goodCopyOf(Object a,int newLength){
Class cl=a.getClass();
if(!cl.isArray())return null;
Class componentType=cl.getComponentType();
int length=Array.getLength(a);
Object newArray=Array.newInstance(componentType, newLength);
System.arraycopy(a, 0, newArray, 0, Math.max(newLength, length));//拷贝数组
return newArray;
}
调用方法
获取Method方法,例如:
Method m=User.class.getMethod("getAge");
invoke(Object obj,Object… paramenters):调用这个对象所描述的方法,并返回该方法的返回值。例如:
User u=new User("sendi",20);
Method m=User.class.getMethod("getAge");
int age=(Integer) m.invoke(u);
System.out.println("age::"+age);
打印结果:age::20
关于放射的基础和应用介绍这么多,它还有很多方法和功能,总的来说它可以在运行时去决定逻辑,使程序更加灵活。