java反射代理机制

来源:互联网 发布:计算机就业前景 知乎 编辑:程序博客网 时间:2024/05/16 04:08

package com.lin.text;

public class Person {

public String name;private String sex;private int age;public void show(){    System.out.println("show::姓名:" + name + "性别:" +sex + "年龄:" + age);}public void shows(String name){    System.out.println("show::姓名:" + name + "性别:" +sex + "年龄:" + age);}@SuppressWarnings("unused")private void showp(){    System.out.println("showp::姓名:" + name + "性别:" +sex + "年龄:" + age);}public String getName() {    return name;}public void setName(String name) {    this.name = name;}public String getSex() {    return sex;}public void setSex(String sex) {    this.sex = sex;}public int getAge() {    return age;}public void setAge(int age) {    this.age = age;}

}

package com.lin.text;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

import org.junit.Test;

public class PersonF {

@Testpublic void main1() throws Exception {    // 获取当前类的实例化对象    Class<Person> clazz = Person.class;    // 1.创建clazz对应的运行时类Person,用的是clazz.newInstance()    // 这里的clazz.newInstance()实际上是调用的是Person类的无参构造器    Person p = clazz.newInstance();    // 2.然后在调用,调用的时候先用clazz.getField(“属性名”)的方法来获取public作用域的属性,然后再往对象里面设值    Field nameF = clazz.getField("name");    nameF.set(p, "我奶妈贼六!");    // 3.获取private作用域的属性值方法比一样,用上面的方法获取不到    //首先应该获取声明的属性    Field sexF = clazz.getDeclaredField("sex");    Field ageF = clazz.getDeclaredField("age");    //将访问权限改为true    sexF.setAccessible(true);    ageF.setAccessible(true);    sexF.set(p, "男");    ageF.set(p, 6);    //3.通过反射调用运行类的方法,首先获取方法    Method showF = clazz.getMethod("show");    Method showpF = clazz.getMethod("showp");    //然后调用方法,没有形参的直接showF.invoke(p);    showF.invoke(p);    //没有设置就会报错     showpF.setAccessible(true);    showpF.invoke(p);    //调用有形参的方法,clazz.getMethod时需要指明参数的类型    Method showsF = clazz.getMethod("shows", String.class);    //有形参的话showsF.invoke(p,形参);传入形参    showsF.invoke(p, "测试入参");}/* * java.lang.Class是反射的源头 * 创建的类通过编译(javac.exe),生成对应点.class文件,之后我们使用的java.exe加载(JVM的类加载器) * .class文件,此。class文件加载到内存以后,就是一个运行时类,放在缓存中,那么这个运行时类本身就是一个Class类 * 1.每个运行时类只加载一次 * 2.有了class实例以后才能进行如下操作 *      1)创建对应的运行时类的对象 *      2)获取对应的运行时类的完整结构(属性、方法、构造器、内部类..) *      3)调用对应的运行时类的指定的结构(属性、方法、构造器) *      4)反射的应用:动态代理 */@SuppressWarnings("rawtypes")@Testpublic void main2() throws Exception {     //方法1    Class clazz = Person.class;    System.out.println(clazz.getName());    System.out.println(String.class.getName());    //方法2.通过运行时类的对象获取    Person p = new Person();    Class clazz2 = p.getClass();    System.out.println(clazz2.getName());    //方法3.通过Class的静态方法    String classNme = "com.lin.text.Person";// Person路径    Class clazz3 = Class.forName(classNme);    System.out.println(clazz3.getName());    //方法4.用类加载器    ClassLoader cl = this.getClass().getClassLoader();    Class clazz4 = cl.loadClass(classNme);    System.out.println(clazz4);}//权限修饰符 变量类型 变量名 @SuppressWarnings("rawtypes")@Testpublic void main3() throws Exception {    Class clazz = Person.class;    Field[] fields = clazz.getDeclaredFields();    for(Field f: fields) {        //1.获取每个属性的权限修饰符        int i = f.getModifiers();        //将权限的索引转变成对应的权限名字        String m = Modifier.toString(i);        //2.获取每个属性的变量类型        String type = f.getType().getName();        //3.获取每个属性 的变量名        String name = f.getName();        System.out.println(m + "-" + type + "-" + name);    }}//获取方法的一些属性@SuppressWarnings("rawtypes")@Testpublic void main4() throws Exception {    Class clazz = Person.class;    //获取运行时类及其父类中public权限的方法    Method[] methods = clazz.getMethods();    for(Method m : methods) {        System.out.println(m.getName() + ": " + Modifier.toString(m.getModifiers()) );    }    //getDeclaredMethods是获取该类的中所有方法    Method[] methods2 = clazz.getDeclaredMethods();    for(Method m : methods2) {        //获取注解        Annotation[] ann = m.getAnnotations();        for(Annotation a : ann) {            System.out.println(a);        }        //获取形参列表        Class rt = m.getReturnType();        //获取异常类型        System.out.println("方法名:" + m.getName() + "-权限修饰符:" + Modifier.toString(m.getModifiers()) + "-注解:" + ann + "-返回值类型:" + rt);    }}

}
Java中反射机制主要是应用在动态代理上
:静态代理类和目标对象的类都是在编译期间确定下来的
:动态代理被代理的对象是一个实现抽象接口类,代理的对象是一个实现了InvocationHandler接口的类
静态代理实现:
package com.lin.text;
/**
* 静态代理模式
*/
//接口
interface Factory {
void show();
}

//被代理类
class FactoryImpl implements Factory {

@Overridepublic void show() {    System.out.println("代理对象实现代理接口");}

}

//代理类,这里实现了接口,很明显他只能服务Factory这个接口
class ProxyFactory implements Factory {

//声明的时候声明成FactoryFactory f;//创建代理类,传入的是一个被代理类的对象public ProxyFactory(Factory f) {    this.f = f;}@Overridepublic void show() {    System.out.println("代理类执行");    f.show();}

}

public class TestSaticProxy {

public static void main(String[] args) {    //创建被代理的对象    FactoryImpl factory = new FactoryImpl();    //创建代理对象,因为是静态代理,所以这个代理只能为FactoryImpl这一个对象做代理,    //当创建新的对象时,将又要创建代理对象,如果被代理的对象很多的话,就要创建很多的代理对象,很不方便    ProxyFactory pf = new ProxyFactory(factory);    pf.show();}

}

动态代理:
package com.lin.text;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
* 动态代理
*/
//被代理类
interface Everything {
void show();
}

//代理类
class EverythingImpl implements Everything {

@Overridepublic void show() {    System.out.println("代理类执行");}

}

//创建动态代理类,注意动态代理都要实现一个InvocationHandler的接口
class MyInnvocationHandler implements InvocationHandler {

//实现了接口的被代理类的对象声明,这里由于是因为不能确定被代理类的对象的类,所以同一用Object类,在调用的时候//根据被代理类的类型做适当的强转即可Object obj;//给被代理对象实例化,返回一个代理类的对象public Object blind(Object obj) {    this.obj = obj;    //三个参数意义(被代理类的类加载器, 被代理类实现的接口, 实现InvocationHandler的类,即动态代理的类)    return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), this);}//当通过代理类的对象发起对被重写的方法调用时,都会转换为如下的invoke方法的调用,即调用具体接口中的方法@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {    //调用被代理对象的方法,获取返回对象    Object rv = method.invoke(obj, args);    return rv;}

}

public class TestDynamicProxy {

public static void main(String[] args) {    //被代理对象    EverythingImpl rs = new EverythingImpl();    //创建实现InnvocationHandler接口的动态代理类对象    MyInnvocationHandler mi = new MyInnvocationHandler();    //调用blind()方法,将被代理对象绑定到代理对象上,即设置代理对象    Object obj = mi.blind(rs);    //根据具体的被代理对象做强转,都是强转成对象的服务接口,这里的sub就是转成Subject接口对象    Everything sub = (Everything)obj;    //调用接口方法    sub.show();    FactoryImpl nike = new FactoryImpl();    obj = mi.blind(nike);    Factory pf = (Factory)obj;    pf.show();}

}

原创粉丝点击