1.反射
反射的练习:
- 用 public void setProperty(Object obj, String propertyName, Object value){} 方法将 反射获取值 封装成一个方法,然后再通过调用方法通过传参的方式调用方法;
注意事项:
- 因为方法中的参数,不知道是不是私有的,所以调用 getDeclaredField() 方法。并设置暴力访问;
public class Tool {
public void setProperty(Object obj, String propertyName, Object value){
//通过反射实现
//通过反射获取对象的字节码文件对象
Class<?> c = obj.getClass();
//通过字节码文件对象,获取对应的成员变量形成一个对象
try {
Field declaredField = c.getDeclaredField(propertyName);
//暴力访问
declaredField.setAccessible(true);
declaredField.set(obj,value);
} catch (Exception e) {
e.printStackTrace();
}
}
}
调用方法
public class ToolText {
public static void main(String[] args) {
Person p = new Person();
// p.name = "阿涛"; // 这里因为 name 是私有属性,不能直接获取
//可以通过自己写的工具来进行获取
Tool tool = new Tool();
tool.setProperty(p, "name", "阿涛");
tool.setProperty(p, "age", 18);
tool.setProperty(p, "address", "安徽安庆");
tool.setProperty(p, "id", "1001");
System.out.println(p);
}
}
动态代理
- 动态代理就是,在程序运行期,创建目标对象的代理对象,并对目标对象中的方法进行功能性增强的一种技术。在生成代理对象的过程中,目标对象不变,代理对象中的方法是目标对象方法的增强方法。可以理解为运行期间,对象中方法的动态拦截,在拦截方法的前后执行功能操作。
代理类在程序运行期间,创建的代理对象称之为动态代理对象。这种情况下,创建的代理对象,并不是事先在Java代码中定义好的。而是在运行期间,根据我们在动态代理对象中的“指示”,动态生成的。也就是说,你想获取哪个对象的代理,动态代理就会为你动态的生成这个对象的代理对象。动态代理可以对被代理对象的方法进行功能增强。有了动态代理的技术,那么就可以在不修改方法源码的情况下,增强被代理对象的方法的功能,在方法执行前后做任何你想做的事情。
通俗而言:
代理就是被代理者没有能力或者不愿意去做某件事情,需要找个人代替自己完成这件事,动态代理业务功能(方法)进行代理的
关键步骤:
- 1.必须要有接口,实现类实现接口(代理通常是基于接口实现的)
- 2.创建一个实现类对象,该对象为业务对象,紧接着为业务对象做一个代理对象
代码来袭:
以前的方法:
业务代码(接口)
public interface UserDao {
void add();
void delete();
void update();
void select();
}
实现类(实现接口)
public class UserDaoImpl 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 select() {
// System.out.println("权限校验");
System.out.println("查询数据");
// System.out.println("日志记录");
}
}
调用实现类方法
public class UserDemo {
public static void main(String[] args) {
UserDaoImpl userDao = new UserDaoImpl();
userDao.add();
userDao.delete();
userDao.update();
userDao.select();
System.out.println("=================================");
//真实的开发环境不应该就输出一句话就完事了
//更多的是实际操作
//通常在操作数据库前后都有额外的步骤,在操作之前一般都会有一个权限校验
//不是任何人都可以操作的
//操作完成后也会留下日志记录
//通过我们简单地分析并改动后,显然实现的我们想要的功能,但是也仅限于这个案例
//如果我们在其他这样的案例中社交到的权限检验和日志记录
//还是以这样的方式进行修改,会显得非常麻烦
}
}
出现问题
- 业务对象的每个方法在调用前后都需要进行权限校验和日志记录。存在大量重复代码.
改变:动态代理
动态代理代码
- 此代码必须实现
InvocationHandler 接口,然后重写其中的invoke 方法
代理者的代码为:
public class InvocationHandlerImpl implements InvocationHandler {
private Object proxy1; //目标对象,将来要给谁做代理,就将谁传进来
//创建一个无参构造,将这个对象传进来
InvocationHandlerImpl(Object proxy1){
this.proxy1 = proxy1;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("权限校验");
Object o = method.invoke(proxy1, args);
System.out.println("日志记录");
return o;
}
}
被代理者的代码:
package com.bigdat.java.day29;
import java.lang.reflect.Proxy;
/*
动态代理
*/
public class Text {
public static void main(String[] args) {
UserDaoImpl userDao = new UserDaoImpl();
// 注意点:向下转型必须是转型为其接口
UserDao p = (UserDao)Proxy.newProxyInstance(userDao.getClass().getClassLoader(),
userDao.getClass().getInterfaces(),
new InvocationHandlerImpl(userDao));
p.add();
p.delete();
p.select();
p.update();
System.out.println("=========================================================================");
TeacherDaoImpl teacherDao = new TeacherDaoImpl();
TeacherDao o = (TeacherDao) Proxy.newProxyInstance(teacherDao.getClass().getClassLoader(),
teacherDao.getClass().getInterfaces(),
new InvocationHandlerImpl(teacherDao));
o.login();
o.zhuce();
}
}
一个代理可以不仅可以代理UserDao,
还可以代理老师
teacherDao 代码:
public interface TeacherDao {
void login();
void zhuce();
}
老师的实现类 TeacherDaoInpl
public class TeacherDaoImpl implements TeacherDao{
@Override
public void login() {
System.out.println("用户登录");
}
@Override
public void zhuce() {
System.out.println("用户注册");
}
}
代理老师的方法和代理User的方法写在一起了
反射练习:通过配置文件,反射出其中的方法;
配置文件如下:
···
className=com.bigdat.java.day29.Person
methodName=fun2
···
反射代码如下:
package com.bigdat.java.day29;
import java.io.FileReader;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.Properties;
/*
通过配置文件运行类中的方法
Properties
一般情况下,配置文件有以下几种格式:基本上都是以键值对的方式存在
格式1:
username: xxx
password: xxx
xxx: xxx
格式2:
<name>className</name>
<value>com.xxx.xxx.xx</value>
格式3:
name=xiaohu
age=18
password=123456
*/
public class ReflexTest1 {
public static void main(String[] args) throws Exception{
//学习反射之前
// Person person = new Person();
// person.fun2();
Properties prop = new Properties();
FileReader fr = new FileReader("D://Softwore_java//projects//基础语法1//src//com//" +
"bigdat//java//day29//configure.txt");
prop.load(fr);
fr.close();
//获取数据
String className = prop.getProperty("className");
System.out.println(className);
String methodName = prop.getProperty("methodName");
System.out.println(methodName);
//通过反射实现
Class<?> c = Class.forName(className);
Constructor<?> con1 = c.getConstructor();
Object o = con1.newInstance();
Method fun2 = c.getDeclaredMethod(methodName, String.class);
fun2.setAccessible(true);
fun2.invoke(o,"你好!");
}
}
反射练习:我给你ArrayList的一个对象,我想在这个集合中添加一个字符串数据,如何实现呢?
package com.bigdat.java.day29;
import java.lang.reflect.Method;
import java.util.ArrayList;
/*
我给你ArrayList<Integer>的一个对象,我想在这个集合中添加一个字符串数据,如何实现呢?
*/
public class ReflexText2 {
public static void main(String[] args) throws Exception {
ArrayList<Integer> list = new ArrayList<Integer>();
list.add(100);
list.add(1023);
//通过反射来实现
Class<? extends ArrayList> c = list.getClass();
Method add = c.getMethod("add", Object.class); // 使用 Object 类型,表示所有类型的数据都能加
add.invoke(list,"我擦");
add.invoke(list,"这都行?");
add.invoke(list,10.23);
}
}
原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/tech/pnotes/244406.html