Java反射机制
2014-12-29 12:28
363 查看
java是一门静态语言,反射是java语言的一个特性,它允程序在运行时(注意不是编译的时候)来进行自我检查并且对内部的成员进行操作。例如它允许一个java的类获取他所有的成员变量和方法并且显示出来。
在开发和设计的时候,我们需要考虑编译时,运行时以及构建时这三个概念。理解这几个概念可以更好地帮助你去了解一些基本的原理。下面是初学者晋级中级水平需要知道的一些问题。
Q.下面的代码片段中,行A和行B所标识的代码有什么区别呢?
A.在行A的代码中,product的值是在编译期计算的,行B则是在运行时计算的。如果你使用Java反编译器(例如,jd-gui)来反编译ConstantFolding.class文件的话,那么你就会从下面的结果里得到答案。
常量折叠是一种Java编译器使用的优化技术。由于final变量的值不会改变,因此就可以对它们优化。Java反编译器和javap命令都是查看编译后的代码(例如,字节码)的利器。
2.在jdk中主要由五个类实现java的反射机制,而他们都位于java.lang.reflect包中
动态获取类的信息以及动态调用方法的功能就是java的反射机制
它能在运行时判断任意一个方法所属的类
在运行时构建任意一个类的对象
在运行时判断任何一个类的成员变量和方法
在运行时调用任意一个类的方法
-class类:代表一个类
-field:代表类的成员方法
-method:代表类的方法
-constructor:代表类的构造方法
-array类:提供动态创建数组,以及访问数组元素的静态方法
3.得到class对象的三种方法
Class<?> classtype=Class.forName("com.se.reflect.Customer")//类的静态方法class.forname
Class<?> classtype1=Customer.class;//类的.class
Class<?> classtype2=(new Customer()).getClass();//对象的getclass方法
5.通过反射对对象进行拷贝的方法
6通过反射访问私有的方法和属性
package com.se.reflect;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class PrivateReflect {
/**
* @param args
*/
public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub
/*
* 通过反射实现对私有方法的调用
*/
PrivateClass p=new PrivateClass();
Class<?> classtype=p.getClass();
Method method=classtype.getDeclaredMethod("sayhello", new Class[]{String.class});
method.setAccessible(true);//正常情况下不能类外部访问私有方法,压制java的访问控制检查
String result=(String)method.invoke(p, new Object[]{"zhangsan"});
System.out.println(result);
/*
* 通过反射修改私有属性
*/
PrivateClass pp=new PrivateClass();
Class<?> classt=pp.getClass();
Field field=classt.getDeclaredField("username");
field.setAccessible(true);
field.set(pp, "lisi");
System.out.println(pp.getname());
}
}
class PrivateClass{
private String username="zhangsan";
public String getname(){
return username;
}
private String sayhello(String str){
String result="hello:"+str;
return result;
}
}
7.代理模式
代理模式的作用就是为其他对象提供一种代理以控制对这个对象的访问,在某些情况下客户不能直接引用另一个对象而代理对象可以在客户端和目标对象中起到中介的作用,代理角色内部含有真实对象的引用
package com.se.proxy;
public class ProxySubject extends Subject {
//代理角色引用了真实角色
private RealSubject realSubject;
@Override
public void request() {
// TODO Auto-generated method stub
this.preRequest();
if(realSubject!=null){
realSubject=new RealSubject();
}
realSubject.request();//真实对象
this.postRequest();
}
private void preRequest(){
System.out.println("pre request");
}
private void postRequest(){
System.out.println(" post request");
}
}
动态代理
package com.se.dynamicproxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class DynamicSubject implements InvocationHandler{//动态代理类实现invocationhandler接口
private Object sub;
public DynamicSubject(Object obj){
this.sub=obj;
}
//实现invoke方法
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.println("before calling"+method);
method.invoke(sub, args);//通过method调用
System.out.println("after calling"+method);
return null;
}
}
在开发和设计的时候,我们需要考虑编译时,运行时以及构建时这三个概念。理解这几个概念可以更好地帮助你去了解一些基本的原理。下面是初学者晋级中级水平需要知道的一些问题。
Q.下面的代码片段中,行A和行B所标识的代码有什么区别呢?
public class ConstantFolding { staticfinal int number1 = 5; staticfinal int number2 = 6; staticint number3 = 5; staticint number4= 6; publicstatic void main(String[ ] args) { intproduct1 = number1 * number2; //line A intproduct2 = number3 * number4; //line B }
A.在行A的代码中,product的值是在编译期计算的,行B则是在运行时计算的。如果你使用Java反编译器(例如,jd-gui)来反编译ConstantFolding.class文件的话,那么你就会从下面的结果里得到答案。
public class ConstantFolding { staticfinal int number1 = 5; staticfinal int number2 = 6; staticint number3 = 5; staticint number4 = 6; publicstatic void main(String[ ] args) { intproduct1 = 30; intproduct2 = number3 * number4; } }
常量折叠是一种Java编译器使用的优化技术。由于final变量的值不会改变,因此就可以对它们优化。Java反编译器和javap命令都是查看编译后的代码(例如,字节码)的利器。
2.在jdk中主要由五个类实现java的反射机制,而他们都位于java.lang.reflect包中
动态获取类的信息以及动态调用方法的功能就是java的反射机制
它能在运行时判断任意一个方法所属的类
在运行时构建任意一个类的对象
在运行时判断任何一个类的成员变量和方法
在运行时调用任意一个类的方法
-class类:代表一个类
-field:代表类的成员方法
-method:代表类的方法
-constructor:代表类的构造方法
-array类:提供动态创建数组,以及访问数组元素的静态方法
3.得到class对象的三种方法
Class<?> classtype=Class.forName("com.se.reflect.Customer")//类的静态方法class.forname
Class<?> classtype1=Customer.class;//类的.class
Class<?> classtype2=(new Customer()).getClass();//对象的getclass方法
package Invoke; import java.lang.reflect.Method; public class InvokeTest { public int add(int param1,int param2){ return param1+param2; } public String echo(String message){ return "hello:"+message; } public static void main(String[] args) throws Exception { // TODO Auto-generated method stub System.out.println("----------method1:new object----------"); InvokeTest test=new InvokeTest(); System.out.println(test.add(1, 2)); System.out.println(test.echo("jason")); System.out.println("----------method1:reflect-------------"); //得到类对象的两种方法 //Class<?> classType=Class.forName("/JavaReflection/src/Invoke/InvokeTest.java"); Class<?> classType=InvokeTest.class; //得到类的实例 Object invoke=classType.newInstance(); System.out.println(invoke instanceof InvokeTest);//对象 是否是类的实例 //通过反射调用方法就必须得到method对象 Method addmethod=classType.getMethod("add", new Class[]{int.class,int.class}); Object addresult=addmethod.invoke(invoke,new Object[]{1,2});//类的实例和参数 System.out.println((Integer)addresult); Method echomethod=classType.getMethod("echo", new Class[]{String.class}); Object echoresult=echomethod.invoke(invoke, "christoph"); System.out.println(echoresult.toString()); } }
5.通过反射对对象进行拷贝的方法
package com.se.reflect; import java.lang.reflect.Field; import java.lang.reflect.Method; public class FieldReflect { //对顾客类进行拷贝的方法 public Object copy(Object object) throws Exception{ Class<?> classtype=object.getClass();//得到类对象 Object copyobject=classtype.getConstructor(new Class[]{}) .newInstance(new Object[]{}); Field[] fields=classtype.getDeclaredFields();//获得对象的所有的成员变量 for (Field f: fields) { String name=f.getName(); String firstletter=name.substring(0,1).toUpperCase(); String getMethodName="get"+firstletter+name.substring(1); String setMethodName="set"+firstletter+name.substring(1);
Method getmethod=classtype.getDeclaredMethod(getMethodName, new Class[]{}); Method setmethod=classtype.getDeclaredMethod(setMethodName, new Class[]{f.getType()}); Object value=getmethod.invoke(object, new Object[]{}); setmethod.invoke(copyobject, new Object[]{value}); } return copyobject; } public static void main(String[] args) throws Exception { Customer cus=new Customer("tom",111111); cus.setId(1L); FieldReflect re=new FieldReflect(); Customer cus2=(Customer) re.copy(cus); System.out.println(cus2.getId()+cus2.getName()+cus2.getAge()); } } //顾客类 class Customer{ private Long id; private String name; private int age; public Customer(){} public Customer(String name,int age){ this.name=name; this.age=age; } public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }
6通过反射访问私有的方法和属性
package com.se.reflect;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class PrivateReflect {
/**
* @param args
*/
public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub
/*
* 通过反射实现对私有方法的调用
*/
PrivateClass p=new PrivateClass();
Class<?> classtype=p.getClass();
Method method=classtype.getDeclaredMethod("sayhello", new Class[]{String.class});
method.setAccessible(true);//正常情况下不能类外部访问私有方法,压制java的访问控制检查
String result=(String)method.invoke(p, new Object[]{"zhangsan"});
System.out.println(result);
/*
* 通过反射修改私有属性
*/
PrivateClass pp=new PrivateClass();
Class<?> classt=pp.getClass();
Field field=classt.getDeclaredField("username");
field.setAccessible(true);
field.set(pp, "lisi");
System.out.println(pp.getname());
}
}
class PrivateClass{
private String username="zhangsan";
public String getname(){
return username;
}
private String sayhello(String str){
String result="hello:"+str;
return result;
}
}
7.代理模式
代理模式的作用就是为其他对象提供一种代理以控制对这个对象的访问,在某些情况下客户不能直接引用另一个对象而代理对象可以在客户端和目标对象中起到中介的作用,代理角色内部含有真实对象的引用
package com.se.proxy;
public class ProxySubject extends Subject {
//代理角色引用了真实角色
private RealSubject realSubject;
@Override
public void request() {
// TODO Auto-generated method stub
this.preRequest();
if(realSubject!=null){
realSubject=new RealSubject();
}
realSubject.request();//真实对象
this.postRequest();
}
private void preRequest(){
System.out.println("pre request");
}
private void postRequest(){
System.out.println(" post request");
}
}
package com.se.proxy; public class StaticProxyTest { /* * 静态代理模式 * //代理模式的作用就是为其他对象提供一种代理以控制对这个对象的访问 * //在某些情况下客户不能直接引用另一个对象而代理对象可以在客户端和目标对象中起到中介的作用 * 代理角色内部含有真实对象的引用 */ public static void main(String[] args) { ProxySubject proxy=new ProxySubject(); proxy.request(); } }
动态代理
package com.se.dynamicproxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class DynamicSubject implements InvocationHandler{//动态代理类实现invocationhandler接口
private Object sub;
public DynamicSubject(Object obj){
this.sub=obj;
}
//实现invoke方法
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.println("before calling"+method);
method.invoke(sub, args);//通过method调用
System.out.println("after calling"+method);
return null;
}
}
package com.se.dynamicproxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Proxy; public class ClientTest { public static void main(String[] args) { RealSubject real=new RealSubject(); InvocationHandler hander=new DynamicSubject(real); Class<?> classtype=hander.getClass(); //下面的代码一次性生成代理 Subject subject= (Subject)Proxy.newProxyInstance(classtype.getClassLoader(), real.getClass().getInterfaces(), hander); subject.request(); System.out.println(subject.getClass()); } }