您的位置:首页 > 职场人生

黑马程序员--反射应用和动态代理

2015-12-22 21:13 666 查看
------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------

第二讲  反射应用和动态代理
一、    通过配置文件运行类中的方法
这个应用有助于我们理解反射的作用。应用场景是这样的,假设我们有三个项目分别为Student、Teacher、Worker,另外还有一个测试类Test用来测试这三个项目。
//学生类
package cn.itcast_02;

public class Student {
public void show(){
System.out.println("我是学生,我爱学习");
}
}<textarea readonly="readonly" name="code" class="java"><br/>

//老师类
package cn.itcast_02;

public class Teacher {
public void show(){
System.out.println("我是老师,我爱教书");
}
}<textarea readonly="readonly" name="code" class="java"><br/>

//工人类
package cn.itcast_02;

public class Worker {
public void show(){
System.out.println("我是工人,我爱工作");
}
}<textarea readonly="readonly" name="code" class="java"><br/>

我们在学习反射之前的做法是这样的,这种编码称为“硬编码”,即把代码写死了。
//测试类1
package cn.itcast_02;

public class Test {
public static void main(String[] args) {
Student s=new Student();
s.show();

Teacher t=new Teacher();
t.show();

Worker w=new Worker();
w.show();
}
}<textarea readonly="readonly" name="code" class="java"><br/>

这样的做法太麻烦,测试代码需要不断的修改。有了反射之后,就能很好的解决这个问题,一般需要和配置文件配合使用。在这里我们用class.txt来代替配置文件,配置文件一般由键值对组成,并且你需要知道有两个键className和methodName22
反射的解决方案如下。
className=???
methodName???<textarea readonly="readonly" name="code" class="java"><br/>

//测试类2
package cn.itcast_02;

import java.io.FileReader;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.Properties;

public class Test2 {
public static void main(String[] args) throws Exception {
// Properties加载文件中的键值对
Properties prop = new Properties();
FileReader fr = new FileReader("class.txt");
prop.load(fr);
fr.close();

// 获取数据
String className = prop.getProperty("className");
String methodName = prop.getProperty("methodName");

// 反射
Class c = Class.forName(className);
Constructor con = c.getConstructor();
Object obj = con.newInstance();

//调用方法
Method m = c.getMethod(methodName);
m.invoke(obj);
}
}<textarea readonly="readonly" name="code" class="java"><br/>

二、    通过反射绕过泛型检查
在学习反射之前,想给指定泛型的集合添加其他类型的数据是做不到的。比如有个集合是ArrayList<Integer> array=new ArrayList<Integer>( ),想实现array.add(“hello”)是无法实现的。但是学习了反射以后,这个功能就可以实现了。通过查看add的源码我们发现,泛型默认的类型是Object,只不过在JDK5以后为了数据的安全加入了泛型机制,但是这个机制仅仅是给编译期看的,真正运行时依然是Object。通过反编译工具查看代码也可以发现,在反编译器中,泛型被去掉了,由此可见泛型检查在运行期是不存在的。
所以如果我们能拿到集合的源码就可以实现如题的功能了。而反射恰好就可以拿到类的源码。反射的解决方案如下。
//代码实现
package cn.itcast_02;

import java.lang.reflect.Method;
import java.util.ArrayList;

public class ArrayDemo {
public static void main(String[] args) throws Exception {
ArrayList<integer> array = new ArrayList<integer>();
Class c = array.getClass();

Method m = c.getMethod("add", Object.class);
m.invoke(array, "hello");
m.invoke(array, "world");
m.invoke(array, "java");
System.out.println(array);
}
}<textarea readonly="readonly" name="code" class="java"><br/>

三、    写一个给类中私有成员变量赋值
public  void  setProperty(Object  obj, String propertyName  value  )
这个方法声明的意思是给obj中的成员变量propertyName赋值为value。这里主要指给私有成员变量赋值,因为除此之外的成员变量可以通过创建对象对其赋值。
//学生类
package cn.itcast_03;

public class Student1 {
private String name;
public int age;

@Override
public String toString() {
return "Student1 [name=" + name + ", age=" + age + "]";
}

}
<textarea readonly="readonly" name="code" class="java"><br/>

//为成员变量赋值的方法
package cn.itcast_03;

import java.lang.reflect.Field;

public class Tool {
public void setProperty(Object obj, String propertyName, Object value)
throws Exception {
//获取obj的字节码文件对象
Class c = obj.getClass();
//获取成员变量propertyName
Field field = c.getDeclaredField(propertyName);
//取消访问检查
field.setAccessible(true);
//赋值
field.set(obj, value);
}
}<textarea readonly="readonly" name="code" class="java"><br/>

//测试类
package cn.itcast_03;

public class ReflectDemo1 {
public static void main(String[] args) throws Exception {
// 给私有成员变量赋值
Student1 s = new Student1();
Tool t = new Tool();
t.setProperty(s, "name", "刘亦菲");
System.out.println(s);
}
}<textarea readonly="readonly" name="code" class="java"><br/>

四、    动态代理
动态代理的应用场景是这样的,假设有一个借口UserDao,他有四个抽象方法add,delete,update,find。另外有一个UserDaoDemo类实现这个借口,实现代码如下
//用户操作接口
package cn.it
4000
cast_04;

public interface UserDao {
public abstract void add();
public abstract void delete();
public abstract void update();
public abstract void find();
}<textarea readonly="readonly" name="code" class="java"><br/>

//用户操作实现类1
package cn.itcast_04;

public class UserDaoImpl implements UserDao {

@Override
public void add() {
System.out.println("增加");

}

@Override
public void delete() {
System.out.println("删除");

}

@Override
public void update() {
System.out.println("修改");

}

@Override
public void find() {
System.out.println("查找");

}

}<textarea readonly="readonly" name="code" class="java"><br/>


但是真实的应用场景往往不是这样的。写代码要符合他的开闭原则,即对扩展开放,对修改关闭。真实的应用场景是在任何操作前都要检查用户权限,在操作后要生成操作日志。所以以上代码改进为如下代码。
//用户操作实现类2
package cn.itcast_04;

public class UserDaoImpl2 implements UserDao {

@Override
public void add() {
System.out.println("检查用户权限");
System.out.println("增加");
System.out.println("生成操作日志");

}

@Override
public void delete() {
System.out.println("检查用户权限");
System.out.println("删除");
System.out.println("生成操作日志");

}

@Override
public void update() {
System.out.println("检查用户权限");
System.out.println("修改");
System.out.println("生成操作日志");

}

@Override
public void find() {
System.out.println("检查用户权限");
System.out.println("查找");
System.out.println("生成操作日志");

}

}<textarea readonly="readonly" name="code" class="java"><br/>

但是假如还有别的类也要实现这样的功能,那么也要在具体实现类中分别加上检查用户权限和生成操作日志,很显然这样的代码不够灵活,这样的实现不好。那么我们可不可以找一个“中介”来给我们实现添加检查用户权限和生成操作日志功能呢。这个“中介”即为动态代理
在Java中java.lang.reflect包下提供了一个Proxy类和一个InvocationHandler接口,通过使用这个类和接口就可以生成动态代理对象。JDK提供的代理只能针对接口做代理。具体用法如下。
//用户操作接口
package cn.itcast_05;

public interface UserDao {
public abstract void add();
public abstract void delete();
public abstract void update();
public abstract void find();
}<textarea readonly="readonly" name="code" class="java"><br/>

//用户操作实现类3
package cn.itcast_05;

public class UserDaoImpl implements UserDao {

@Override
public void add() {
System.out.println("增加");

}

@Override
public void delete() {
System.out.println("删除");

}

@Override
public void update() {
System.out.println("修改");

}

@Override
public void find() {
System.out.println("查找");

}

}<textarea readonly="readonly" name="code" class="java"><br/>

package cn.itcast_05;

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

public class MyInvocationhandler implements InvocationHandler {

private Object target;

public MyInvocationhandler(Object target) {
this.target = target;
}

@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.println("检查用户权限");
Object result = method.invoke(target, args);
System.out.println("生成操作日志");
return result;
}
}<textarea readonly="readonly" name="code" class="java"><br/>

//代理测试类
package cn.itcast_05;

import java.lang.reflect.Proxy;

public class Test {
public static void main(String[] args) {
UserDao ud = new UserDaoImpl();
ud.add();
ud.delete();
ud.update();
ud.find();
System.out.println("----------------");

// 创建动态代理对象
// 准备对ud对象做代理对象
MyInvocationhandler halder = new MyInvocationhandler(ud);
UserDao proxy = (UserDao) Proxy.newProxyInstance(ud.getClass()
.getClassLoader(), ud.getClass().getInterfaces(), halder);
proxy.add();
proxy.delete();
proxy.update();
proxy.find();

}
}<textarea readonly="readonly" name="code" class="java"><br/>

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