在我们平时的项目开发中,虽然很少用到反射机制,但实际上很多设计、开发都与反射机制有关,例如利用反射实现工厂设计模式,利用反射实现动态代理,利用反射获取注解信息等等,下面就基于这三种应用进行相关的描述
一、利用反射实现工厂设计模式
interface IMessage {
public void send();
}
class NetMessage implements IMessage {
@Override
public void send() {
System.out.println("我是netMessage");
}
}
class ServiceMessage implements IMessage {
@Override
public void send() {
System.out.println("我是serviceMessage");
}
}
class Factory {
private Factory(){}
public static IMessage getInstance(String className){
try{
return (IMessage) Class.forName(className).getDeclaredConstructor().newInstance();
}catch(Exception e){
e.printStackTrace();
}
}
}
public class Test {
public static void main(String[] args) {
IMessage iMessage = Factory.getInstance("NetMessage");
iMessage.send();
}
}
这样我们就可以在主类中只传入一个带有包名+类名的字符串就可以从工厂类中获取到对象的实例,避免了在工厂类中重复的类型判断语句
二、利用反射实现动态代理
jdk的动态代理主要和Proxy类和InvocationHandler接口相关
InvocationHandler是代理实例调用处理程序实现的接口
Proxy类提供用于创建动态代理和实例的静态方法,它还是由这些方法创建的所有动态代理类的超类
interface IMessage{
public void send();
}
class RealHandler implements IMessage{
@Override
public void send() {
System.out.println("真实业务类输出");
}
}
class ProxyHandler implements InvocationHandler{
private Object target;
public Object bind(Object target){
this.target = target;
return Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
// 利用反射机制返回一个Proxy代理类
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
log(method.getName()); //实现日志打印功能,代理类相对于真实业务类多出来的方法
method.invoke(target,args); //调用真实业务类的send方法
return null;
}
public void log(String str){
System.out.println(str);
}
}
public class Solution {
public static void main(String[] args){
IMessage iMessage = new RealHandler();
ProxyHandler proxyHandler = new ProxyHandler();
IMessage proxy = (IMessage) proxyHandler.bind(iMessage);
proxy.send();
}
}
三、自定义注解和利用反射获取注解信息
一个基本的注解主要由以下三部分组成
(1)@Target 是用来限定注解是用在哪些Java元素上面的,ElementType枚举类型定义如下:
public enum ElementType {
/** 类,接口(包括注解类型)或枚举的声明 */
TYPE,
/** 属性的声明 */
FIELD,
/** 方法的声明 */
METHOD,
/** 方法形式参数声明 */
PARAMETER,
/** 构造方法的声明 */
CONSTRUCTOR,
/** 局部变量声明 */
LOCAL_VARIABLE,
/** 注解类型声明 */
ANNOTATION_TYPE,
/** 包的声明 */
PACKAGE
}
(2)@Retention用来修饰自定义注解的生命周期
注解的生命周期有三个阶段:1、Java源文件阶段;2、编译到class文件阶段;3、运行期阶段,分别对应了枚举类RetentionPolicy的SOURCR、CLASS、RUNTIME
(3)用@interface来自定义一个注解
自定义注解并利用反射获取注解信息
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation{
public String name();
public int age() default 12;
}
class Message{
@MyAnnotation(name="zhangsan")
public void send(String msg){
System.out.println(msg);
}
}
public class Solution {
public static void main(String[] args){
try{
Method method = Message.class.getMethod("send",String.class);
MyAnnotation myAnnotation = method.getAnnotation(MyAnnotation.class);
String msg = myAnnotation.name() + "----" + myAnnotation.age();
method.invoke(Message.class.getDeclaredConstructor().newInstance(),msg);
} catch(Exception e){
e.printStackTrace();
}
}
}