您的位置:首页 > 编程语言 > Java开发

java反射代理机制

2017-12-13 14:43 274 查看
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 {

@Test
public 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")
@Test
public 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")
@Test
public 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")
@Test
public 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 {

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


}

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

class ProxyFactory implements Factory {

//声明的时候声明成Factory
Factory f;

//创建代理类,传入的是一个被代理类的对象
public ProxyFactory(Factory f) {
this.f = f;
}

@Override
public 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 {

@Override
public 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方法的调用,即调用具体接口中的方法
@Override
public 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();
}


}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  反射与代理