20200304-Java设计模式
一、Java反射技术-反射(Reflection)
Java反射技术应用广泛,能够配置:类的全限定名、方法和参数,完成对象的初始化,反射某些方法
内容:对象构建、反射方法、注解、参数、接口等。
在Java中反射是通过包java.lang.reflect.*实现的。
反射的前提: 已经加载过这个类,就可以通过类名来寻找到这个类的所有相关信息。(一看到蜡笔小新四个字就会在脑子里想到小新的模样,前提是知道小新的模样)
反射机制:通过一个抽象的类名能够在自己记忆(加载类的内存)中找到相匹配的类的具体信息。
1.通过反射构建对象
优点:只要配置就可以生成对象,可以解除程序的耦合度,比较灵活。
缺点:运行比较慢。
2.反射方法
需要先获取方法对象,得到了方法才能去反射。
3.示例
01:反射对象,获取方法
package com.lean.ssm.chapter2.reflect;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class ReflectServiceImpl {
public void sayHello(String name) {
System.out.println("Hello!" + name);
}
public Object reflect() {
ReflectServiceImpl obj = null;
try {
obj = (ReflectServiceImpl) Class.forName("com.lean.ssm.chapter2.reflect.ReflectServiceImpl").newInstance();
Method mm = obj.getClass().getMethod("sayHello", String.class);
mm.invoke(obj, "zhangs");
} catch (NoSuchMethodException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return obj;
}
}
调用:
public static void main(String[] args) {
ReflectServiceImpl rr = new ReflectServiceImpl();
rr.reflect();
}
结果:
02:反射对象构造
Class clazz = Class.forName("com.lean.ssm.reflect.Student");//找到加载过的类
Class suClazz = clazz.getSuperclass();//取得父类
System.out.println("father:" + suClazz.getName());
Class[] ClassInfo = clazz.getInterfaces();//取得接口
for (Class class1 : ClassInfo) {
System.out.println("interface:" + class1.getName());
}
System.out.println("*************");
Constructor[] cons = clazz.getConstructors();//获取公有的构造器
for (Constructor con : cons) {
System.out.println(con.getName());
System.out.println("/");
System.out.println(con.getModifiers());//获取构造器的修饰符 1-public 2-private
}
System.out.println("--------------------");
Constructor[] cons2 = clazz.getDeclaredConstructors();//获取所有构造器,包括私有
for (Constructor con : cons2) {
System.out.println(con.getName());
System.out.println("/");
System.out.println(con.getModifiers());
System.out.println("==============");
Class[] parm =con.getParameterTypes();//获取构造器的参数列表的参数类型
for (Class aa : parm) {
System.out.println("type:"+aa.getName());
}
}
//01
Student stu = (Student) clazz.newInstance();//创建对象
System.out.println(stu);
//02
Constructor c = clazz.getConstructor(String.class);
Student stu2 = (Student)c.newInstance("school");//相当于 Student stu = new Student();
System.out.println(stu2);
System.out.println(stu2.school);
//03
Constructor c2 = clazz.getDeclaredConstructor(String.class,int.class);//方法接收参数都是class类型
c2.setAccessible(true);//解除访问修饰符的限制,可以对私有方法强制调用
Student stu3 = (Student)c2.newInstance("zhangs",5);
System.out.println(stu3);
03:反射获取类的全部方法
Class clazz = Class.forName("com.lean.ssm.reflect.Student");
// Method[] me = clazz.getMethods();//获取到类的所有的公有方法(含equals等方法)
Method[] me = clazz.getDeclaredMethods();//获取类的所有方法,包含公有私有(不含equals等方法)
for (Method method : me) {
System.out.println(method.getName());
System.out.println(method.getReturnType());
System.out.println(method.getModifiers());
System.out.println("-");
Class[] cl = method.getParameterTypes();
if(cl!=null&&cl.length>0) {
for (Class clzz : cl) {
System.out.println(clzz);
}
}
System.out.println("***************************");
}
04:获取类的属性和包
属性:
Class clazz = Class.forName("com.lean.ssm.reflect.Student");
// Field[] ff = clazz.getFields();//获取类的公有的属性,包含父类的共有属性
Field[] ff = clazz.getDeclaredFields();//获取本类的所有的属性,包括私有
for (Field field : ff) {
System.out.println(field.getModifiers());
System.out.println(field.getType());
System.out.println(field.getName());
}
包:
Package p = clazz.getPackage();//获取类所在的包
System.out.println(p.getName());
```java
05:通过反射调用类中的指定方法、指定属性
指定方法:
Class c = Class.forName("com.lean.ssm.reflect.Student");
//注意:下面无论是反射嗲用setInfo方法还是test方法
//都调用的是obj对象的方法,obj实际上就是student对象
Constructor con = c.getConstructor();//获取无参构造
Object obj = con.newInstance();//使用无参构造创建对象
//调用公有方法
//得到名称是setInfo,参数是String,String的方法
//方法第一个参数是调用的方法名,第二个是被调用的方法的参数类型
Method mm = c.getMethod("setInfo", String.class,String.class);
//调用方法,参数1是需要实例化的对象,后面的参数是调用当前方法的实际参数
mm.invoke(obj, "nn","ss");
//调用私有方法
Method m1 = c.getDeclaredMethod("test", String.class);
m1.setAccessible(true);//解除私有封装下面可以强制调用私有方法
m1.invoke(obj, "ss");
//调用一个重载方法
Method m2 = c.getMethod("setInfo", int.class);
m2.invoke(obj, 5);
//有返回值的方法
Method m3 = c.getMethod("getSchool");//获取方法名为getSchool并且没有返回值的方法
String school = (String) m3.invoke(obj);//调用有返回值但是没有参数方法
System.out.println(school);
指定属性:
Class c = Class.forName("com.lean.ssm.reflect.Student");
//反射创建一个对象
Constructor con = c.getConstructor();
Student stu = (Student) con.newInstance();
//公有的
Field f = c.getField("school");//获取名称为school的属性
f.set(stu, "oneschool");//对stu对象的school属性设置值:oneschool
String str = (String) f.get(stu);//获取stu对象的school属性的值
System.out.println(str);
//私有属性
Field f1 = c.getDeclaredField("privatefield");//获取名称为privatefield的属性
f1.setAccessible(true);
f1.set(stu, "ol");
String str1 = (String) f1.get(stu);
System.out.println(str1);
结论:对象在反射机制下生成后,反射了方法,增强了Java的可配置性和可扩展性,其中SpringIOC就是一个典型的例子。
二、动态代理
1.动态代理(反射的关键应用)
**意义:**生成一个占位(又称代理对象),来代理真实对象,从而控制真实对象的访问。
**理解:**在真实对象访问之前或者之后加入对应逻辑,或者根据其他规则控制是否使用真实对象。
步骤:
(1)代理对象和真实对象建立代理关系
(2)实现代理对象的代理逻辑方法
JDK代理方法:
public interface ItestProxy {
void test1();
void test2();
}
public class TestProxyImpl implements ItestProxy {
@Override
public void test1() {
System.out.println("执行test1");
}
@Override
public void test2() {
System.out.println("执行test2");
}
}
/**
* 动态代理类
* @author BMX
*
*/
public class ProxyDemo implements InvocationHandler {
Object obj;//被代理的对象
public ProxyDemo(Object obj) {
this.obj = obj;
}
@Override
public Object invoke(Object arg0, Method arg1, Object[] arg2) throws Throwable {
System.out.println(arg1.getName()+"开始执行");
Object obj1 = arg1.invoke(this.obj, arg2);//执行的是指定代理对象的指定方法
System.out.println(arg1.getName()+"执行结束");
return obj1;
}
}
ItestProxy test = new TestProxyImpl();
/**
* 注意:如果一个对象想要通过Proxy.newProxyInstance方法被代理
* 那么这个对象的类一定要有相应的接口
* 就像本类中的ItestProxy接口和实现类TestProxyImpl一样
*/
test.test1();
test.test2();
/**
* 需求:在执行test1、2方法时,需要加入一些东西
* 方法执行前打印开始执行
* 方法执行后打印执行完毕
* 打印的方法名需要跟当前运行的方法名一致
*/
System.out.println("**********************");
InvocationHandler ih = new ProxyDemo(test);
/**
* Proxy.newProxyInstance(参数1, 参数2, 参数3);
* 参数1=动态代理类的对象.getClass().getClassLoader()
* 参数2=被代理的对象的接口=test.getClass().getInterfaces()
* 参数3=代理对象=ih
*
* 返回值:成功被代理后的对象-(test被代理成功之后)
* 返回的是object类型,需要根据当时的情况去转换类型
*/
ItestProxy t = (ItestProxy) Proxy.newProxyInstance(ih.getClass().getClassLoader(), test.getClass().getInterfaces(), ih);
t.test1();
t.test2();
结果
CGLIB动态代理
优势:不需要提供接口,只需要一个非抽象类就能实现动态代理。
拦截器
程序设计者通常会设计一个拦截器接口供开发者使用,开发者只需要知道拦截器接口的方法、含义和作用即可。
java拦截器实现功能类似于SpringAOP,实现拦截部分方法,一般用于网站登录: 登录进入A页面,未登录进入B页面。
实现方法有两种 :
实现Interceptor 接口 -实现接口需要实现其中所有方法
继承HandlerInterceptorAdapter类-继承抽象类则一般实现preHandle方法即可。
接口:
public interface Interceptor {
public boolean before(Object proxy,Object target,Method method,Object[] args);
public void around(Object proxy,Object target,Method method,Object[] args);
public void after(Object proxy,Object target,Method method,Object[] args);
}
实现类:
public class InterceptorJdkProxy implements InvocationHandler {
private Object target;//真实对象
private String interceptorClass=null;//拦截器全限定名
public InterceptorJdkProxy(Object target, String interceptorClass) {
this.target = target;
this.interceptorClass = interceptorClass;
}
/**
* 绑定委托对象并返回一个【代理占位】
* @param target 真实对象
* @return 代理对象【占位】
*/
public static Object bind(Object target,String interceptorClass) {
return Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new InterceptorJdkProxy(target,interceptorClass)
);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if(interceptorClass == null) {
return method.invoke(target, args);
}
Object result = null;
Interceptor inter = (Interceptor) Class.forName(interceptorClass).newInstance();
if(inter.before(proxy, target, method, args)) {
result = method.invoke(target, args);
}else {
inter.around(proxy, target, method, args);
}
inter.after(proxy, target, method, args);
return result;
}
}
测试:
main(){
A proxy = (A) InterceptorJdkProxy.bind(new AImpl(),"拦截器全类名");
proxy.方法();
}