反射与动态代理

反射

两个问题

通过直接new的方式或者反射的方式都可以直接调用公共的结构,开发中用哪个?

答:建议直接new对象,体现了绝大多数的情况。但有时候会使用反射,体现了动态性(编译的时候不能确定)。

发射机制与面向对象中的封装性是不是矛盾的?如何看待两个技术?

答:不矛盾。你可以调,但是我这里可能封装的更好。反射解决的是能不能调的问题,封装性是建议怎么调的问题。

Class

java.lang.Class类的理解

  1. 类的加载过程:
    • 程序经过javac.exe命令后,会生成一个或者多个字节码文件(.class结尾的)
    • java.exe对某个字节码文件进行解释运行,相当于将某个字节码文件加载到内存中了。此过程称为类的加载。
    • 加载到内存中的类,我们称为运行时类,此运行时类,就作为Class的一个实例。
  2. 运行时类加载到内存中后,会缓存一段时间,在此时间内,我们可以通过不同的方式来获取此运行时类。

我们常用的三种之外,还有一个类加载器方法:(了解)

ClassLoader classloader = Clazz.class.getClassLoader();
Class clazz = classloader.loadClass("packagename");

接口,基本类型,数组,内部类(匿名),void,注解等等都算Class类型。只要数组的类型和维度相同,那么就都是一个Class。

类的加载过程

类的加载,链接,初始化。这三个步骤合在一起就是类的加载。字节码文件读入内存创建一个Class对象,次过程有类加载器进行。

初始化中执行域初始化操作(虚拟机会保证一个类的方法在多线程环境中被正确的加锁和同步)

Classloader就是用来把类加载进内存。

  • 引导类加载器:用C++便携,负责Java平台核心库,用来装载核心类库。(皇室成员)我们没办法获取到。
  • 扩展类加载器(jre里的jar包)
  • 系统类加载器

我们常用的类加载器是自低往上获取到的。CLAZZ.class.getClassLoader()

使用ClassLoader加载配置文件

properties就是一个文件,类似于xml

创建运行时类的对象

 Class<Person> personClass = Person.class;
        Person person = personClass.getDeclaredConstructor().newInstance();//隐含着调用了默认构造器
        System.out.println(person);

反射的动态性:就是给一个字符串path,可以通过反射来创建对象。

获取运行时类的完整结构

获取当前运行时类及其父类为public的Field:

Field[] fields = clazz.getFields();

获取自己的所有权限的Field:(不包含父类的属性)

Field[] fields = clazz.getDeclaredFields();
 int modifiers = f.getModifiers();

private java.lang.String com.sunny.Person.name
2
int com.sunny.Person.age
0
public int com.sunny.Person.id
1

同理,获取运行时方法也是相同的步骤。

动态代理

静态代理:使用一个代理将对象包装起来,然后该代理取代原始对象。任何对原始对象的调用都要通过代理。特征是代理类和目标对象的类都是在编译期间定确定下来的,这样不利于程序的扩展。同时每一个代理类只能为一个接口服务,这样一来,程序开发中必然产生过多的代理,最好是通过一个代理类完成全部的代理功能

动态代理总体的思路是在运行期间创建一个代理类,你加载哪个类,我就创建哪个类的代理类。同时呢,因为代理类含有有很多被代理类的接口。我就看一下你实现了哪些接口,我也实现相同的接口。

一个代理类就可以搞定所有的类。

package com.ahyer;

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

interface Human {
    String getBelief();

    void set(String food);
}

class Superman implements Human{

    @Override
    public String getBelief() {
        return "我相信我可以飞";
    }

    @Override
    public void set(String food) {
        System.out.println("我喜欢吃"+food);
    }
}

/*要想实现动态代理需要解决的问题。
问题一:如何根据加载到内存中的被代理类动态的创建一个代理类及其对象?
问题二:当通过代理类的对象调用方法时,如何动态的去调用被代理类中的同名方法?
*/

class ProxyFactory {
    //通过调用此方法,返回一个代理类的对象。解决问题一
    public static Object getProxyInstance(Object obj) {
        return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
               //proxy代理类。
                Object invoke = method.invoke(obj, args);
                return invoke;
            }
        });
    }
}
public class ProxyTest {
    public static void main(String[] args) {
        Superman superman = new Superman();
        Human proxyInstance = (Human) ProxyFactory.getProxyInstance(superman);
        System.out.println(proxyInstance.getBelief());
        proxyInstance.set("木须肉");
    }
}
/*
我相信我可以飞
我喜欢吃木须肉
*/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值