【JavaSE】反射基础与动态代理案例

目录

一 、概述

二 、Class类

获取class对象的三种方法

方法一:直接通过一个class的静态变量class获取:

方法二:如果我们有一个实例变量,可以通过该实例变量提供的getClass()方法获取:

方法三:如果知道一个class的完整类名,可以通过静态方法Class.forName()获取:

三 、获取类的构造方法

四 、获取类的父类与实现接口

五 、instanceof运算符与判断类型与类型之间的关系

六 、获取成员变量与调用

七 、获取所有方法与调用

八 、代理模式

1.静态代理

2.动态代理


一 、概述

        Java 反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为 Java 语言的反射机制。简单来说,反射机制指的是程序在运行时能够获取自身的信息。在 Java 中,只要给定类的名字,就可以通过反射机制来获得类的所有信息。
        Java 反射机制在服务器程序和中间件程序中得到了广泛运用。在服务器端,往往需要根据客户的请求,动态调用某一个对象的特定方法或者为属性赋值。例如:在主流的 ORM 框架的实现中,运用 Java 反射机制可以读取任意一个 JavaBean 的所有属性,或者给这些属性赋值。
        Java 反射机制主要提供了以下功能,这些功能都位于java.lang.reflect包。

二 、Class类

        想要实现反射,Class类是不可或缺的

        我们可以通过创建对应的Class实例来获得该class的所有信息,包括类名、包名、父类、实现的接口、所有方法、字段(成员变量)等。

        因此,如果获取了某个Class实例,我们就可以通过这个Class实例获取到该实例对应的class的所有信息。这种通过Class实例获取class信息的方法称为反射(Reflection)。

获取class对象的三种方法

方法一:直接通过一个class的静态变量class获取:
Class cls = String.class;
方法二:如果我们有一个实例变量,可以通过该实例变量提供的getClass()方法获取:
String s = "Hello";
Class cls = s.getClass();
方法三:如果知道一个class的完整类名,可以通过静态方法Class.forName()获取:
Class cls = Class.forName("java.lang.String");

三 、获取类的构造方法

        如果通过反射来创建新的实例,可以调用Class提供的newInstance()方法:

        调用Class.newInstance()的局限是,它只能调用该类的public无参数构造方法。如果构造方法带有参数,或者不是public,就无法直接通过Class.newInstance()来调用。

我们先创建一个Exmple类,接下来调用这个类的构造方法

    class Example{
    private Example(String a){
        System.out.println("Example类的有参构造:"+a);
    }

    protected Example(float a){
        System.out.println("Example类的有参构造:"+a);
    }

    public Example(){
        System.out.println("Example类的无参构造!");
    }

    public Example(int a){
        System.out.println("Example类的有参构造:"+a);
    }
    public Example(int a,double b){
        System.out.println("Example类的有参构造:"+a+","+b);
    }

        当我们想要调用构造方法时

        Class cls =Example.class;

        Example example = (Example) cls.newInstance();
        //查看所有构造方法
        System.out.println("所有的构造方法:");
        Constructor[] constructors =cls.getDeclaredConstructors();
        for (Constructor constructor:constructors){
            System.out.println(constructor);
        }
        System.out.println("------------------------------");
        // 获取构造方法
        Constructor constructor =cls.getConstructor();
        Constructor constructor1 =cls.getConstructor(int.class);
        Constructor constructor2 =cls.getConstructor(int.class,double.class);

        //调用构造方法
        Example example1 =(Example) constructor.newInstance();//无参
        Example example2 = (Example) constructor1.newInstance(1024);//有参
        Example example3 = (Example) constructor2.newInstance(1024,3.1415926);//有参
        //调用私有构造方法
        Constructor constructor3 =cls.getDeclaredConstructor(String.class);
        constructor3.setAccessible(true);
        Example example4= (Example) constructor3.newInstance("just");//私有+有参

四 、获取类的父类与实现接口

        //父类
        Class superClass = FileInputStream.class.getSuperclass();
        System.out.println("父类:"+superClass.getName());

        //接口
        System.out.println("实现接口列表:");
        Class[] in =StringBuilder.class.getInterfaces();
        for (Class a :in) {
            System.out.println(a.getName());
        }

五 、instanceof运算符与判断类型与类型之间的关系

        //instanceof运算符
        Object obj = Integer.valueOf(153);
        System.out.println("是否位Integer类型?:"+(obj instanceof Integer));
        System.out.println("是否位Double类型?:"+(obj instanceof Double));
        System.out.println("是否位Number类型?:"+(obj instanceof Number));
        System.out.println("是否位Comparable接口?:"+(obj instanceof Comparable));

        System.out.println("------------------------------------------");

        //isAssignableFrom()方法 判断类型与类型之间的关系
        System.out.println("Integer <= Integer? "+Integer.class.isAssignableFrom(Integer.class));
        System.out.println("Integer <= Number? "+Integer.class.isAssignableFrom(Number.class));
        System.out.println("Number <= Integer? "+Number.class.isAssignableFrom(Integer.class));
        System.out.println("Double <= Integer? "+Double.class.isAssignableFrom(Integer.class));
        System.out.println("Comparable <= Integer? "+Comparable.class.isAssignableFrom(Integer.class));

六 、获取成员变量与调用

        我们可以通过Class实例获取所有Field对象

        Person person =new Person("葫芦娃",16);
        Class cls =person.getClass();
        Field[] fields = cls.getDeclaredFields();
        for (Field field : fields) {
            System.out.println("成员变量名称:"+field.getName());
            //判断是否为私有变量
            if (!field.isAccessible()){
                //可访问私有变量
                field.setAccessible(true);
            }
            System.out.println("成员变量内容:"+field.get(person));
        }
    }

七 、获取所有方法与调用

        我们已经能通过Class实例获取所有Field对象,同样的,可以通过Class实例获取所有方法(Method类型的对象)

        Class cls = String.class;

        //所有方法(包括父类)
//        Method[] methods = cls.getMethods();

        //只含该类中方法
        Method[] methods = cls.getDeclaredMethods();

        for (Method method : methods) {
            System.out.println("方法的访问修饰符:"+ Modifier.toString(method.getModifiers()));
            System.out.println("方法的返回值类型:"+method.getReturnType());
            System.out.println("方法的名称:"+method.getName());

            Parameter[] parameters = method.getParameters();
            for (Parameter parameter : parameters) {
                System.out.println(parameter.getName());
                System.out.println(parameter.getType());
                System.out.println("-----------------------");
            }

            System.out.println();
        }

        调用静态方法

        // 获取Integer.parseInt(String)方法,参数为String:
        Method m = Integer.class.getMethod("parseInt", String.class);
        
        // 调用该静态方法并获取结果:
        Integer n = (Integer) m.invoke(null, "12345");
        
        // 打印调用结果:
        System.out.println(n);

        调用非public方法

        同样我们需要将getMethod()改为getDeclaredMethod()并将setAccessible()设置为true

public class Main {
    public static void main(String[] args) throws Exception {
        Person p = new Person();
        Method m = p.getClass().getDeclaredMethod("setName", String.class);
        m.setAccessible(true);
        m.invoke(p, "Bob");
        System.out.println(p.name);
    }
}

class Person {
    String name;
    private void setName(String name) {
        this.name = name;
    }
}

八 、代理模式

        代理模式:给某一个对象提供一个代理,并由代理对象来控制对真实对象的访问。代理模式是一种结构型设计模式。
        代理模式角色分为 3 种:
        ●Subject抽象主题角色):定义代理类和真实主题的公共对外方法,通常被设计成接口;
        ●RealSubject真实主题角色):真正实现业务逻辑的类;
        ●Proxy代理主题角色):用来代理和封装真实主题;
        代理模式的结构比较简单,其核心是代理类,为了让客户端能够一致性地对待真实对象和代理对象,在代理模式中引入了抽象层。

1.静态代理

subject接口

public interface Subject {
    void request();
}

 被代理类

public class RealSubject implements Subject {
    public void request(){
        System.out.println("逻辑业务1");
        System.out.println("逻辑业务2");
        System.out.println("逻辑业务3");
    }
}

 代理类


public class SubjectProxy implements Subject {
     private Subject target;
     public SubjectProxy(){
         target =new RealSubject();
     }

    @Override
    public void request() {
        System.out.println("begin-----------------");
        target.request();
        System.out.println("end-------------------");
    }
}

测试 

        Subject proxy =new SubjectProxy();
        proxy.request();

 输出

        通过静态代理,我们达到了功能增强的目的,而且没有侵入原代码,这是静态代理的一个优点。
        虽然静态代理实现简单,且不侵入原代码,但是,当场景稍微复杂一些的时候,静态代理的缺点也会暴露出来。
1、 当需要代理多个类的时候,由于代理对象要实现与目标对象一致的接口,有两种方式:
只维护一个代理类,由这个代理类实现多个接口,但是这样就导致代理类过于庞大
新建多个代理类,每个目标对象对应一个代理类,但是这样会产生过多的代理类
2、 当接口需要增加、删除、修改方法的时候,目标对象与代理类都要同时修改,不易维护。

2.动态代理

        动态代理的处理类

public class LogInvocationHandlerImpl implements InvocationHandler {

    private Object target;

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

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("方法" + method.getName() + "开始执行!!");
        Object returnValue = method.invoke(target, args);
        System.out.println("方法" + method.getName() + "开始执行!!");
        return returnValue;
    }
}

        接下来我们分别通过两个案例来实现动态代理

        OrderService接口

public interface OrderService {
	void createOrder();
	void closeOrder();
}

         OrderServiceImpl类

public class OrderServiceImpl implements OrderService{
	@Override
	public void createOrder() {
		System.out.println("生成新的订单!");
	}
	
	@Override
	public void closeOrder() {
		System.out.println("关闭当前订单!");
	}
}

        UserService接口 

public interface UserService {
    void select();
    void update();
}

         UserServiceImpl类

public class UserServiceImpl implements UserService{

    @Override
    public void select() {
        System.out.println("select * ..................");
        System.out.println("数据库中完成用户信息的查询执行!");
    }

    @Override
    public void update() {
        System.out.println("update ...................");
        System.out.println("数据库中用户状态的更新执行!");
    }

}

        Client类

public class Client {
    public static void main(String[] args) {
        //案例一:UserService

        //创建一个将传给代理类的调用请求处理器,处理所有的代理对象上的方法调用
        //这里创建的是一个自定义的日志处理器,须传入实际的执行对象 userServiceImpl
        LogInvocationHandlerImpl handler =new LogInvocationHandlerImpl(new UserServiceImpl());
        //创建UserService接口的动态代理对象
        UserService proxy = (UserService) Proxy.newProxyInstance(
                UserService.class.getClassLoader(),//获取对应的 ClassLoader
                new Class[]{UserService.class},//获取所有接口的Class,这里的UserServiceImpl只实现了一个接口UserService
                handler//目标对象
        );

        proxy.select();//调用select方法
        System.out.println();
        proxy.update();//调用update方法
        System.out.println("-----------------------");


        //案例二:OrderService

        OrderServiceImpl orderServiceTarget =new OrderServiceImpl();
        LogInvocationHandlerImpl handler1 = new LogInvocationHandlerImpl(orderServiceTarget);
        OrderService proxy1 = (OrderService) Proxy.newProxyInstance(
                orderServiceTarget.getClass().getClassLoader(),
                orderServiceTarget.getClass().getInterfaces(),
                handler1);

        proxy1.createOrder();
        System.out.println();
        proxy1.closeOrder();
        System.out.println("----------------------");
        //最后分别查看两个代理类
        System.out.println("UserServiceImpl代理类:"+proxy.getClass());
        System.out.println("OrderServiceImpl代理类:"+proxy1.getClass());
    }
}

        输出结果 

        动态代理是通过Proxy创建代理对象,然后将接口方法“代理”给InvocationHandler完成的

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值