反射与动态代理的学习

1.
        {
        class Perosn(){}
            通过反射创建运行时类的对象的方式

                1.new + 构造器(Person();)

                通过反射实现
                2.clazz.newInstance();
                3.类名.class.getDeclaredConstructors().newInstance();

            获取Class的实例
                1.Person.class;
                2.Person p = new Perosn();
                p.getClass();

构建Class的一些结构
            3.调用Class中的静态方法
                Class.forName("运行时类的相对目录\(根目录)")
        }
    
    
一:关于反射的理解:Reflection(反射)时被视为动态语言的关键,反射机制允许程序执行期间借助与Reflection API取得任何类的内部信息,
                并能直接操作任意对象的内部属性及方法
二:框架= 反射+注解 +设计模式

三:反射的动态性:FanShe\src\Text\NewInstanceTest 中的例题。

四:反射机制提供的功能

2

关于java。long.Class的理解
1.类的加载过程:
    程序经过java.exe命令以后,会生成一个或多个字节码文件(.Class)结尾。
    接着我们使用java.exe命令对某个字节码文件进行解释运行。相当于将某个字节码文件
    加载到内存中。此过程  就称为类的加载。加载到内存中的类,我们就称为运行时类,此
    运行时类,就作为Class的一个实例。

2.换句话说,Class的实例就对应着一个运行时类。
3.加载到内存中的运行时类,会在缓存区中缓存一定的时间,我们可以通过不同的方式来获取
此运行时的类。

3.类的加载器(classloader)

        1.类加载器的作用

        将class文件字节码加载到内存中,并将这些静态数据转换成方法区的运行时数据结构,然后再堆中生产一个这个类的java.lang.Class对象,作为方法区中类数据的访问入口

        2.使用classloader加载SRC下的文件

   Properties ps = new Properties();
        //读取配置文件的方式一 此时的文件默认在当前的module下。
//        FileInputStream fis = new FileInputStream("L3.properties");
//        ps.load(fis);

        //读取配置文件的方式二;使用ClassLoader
        //配置文件默认为:当前module的src下
        ClassLoader classLoader = ClassLoaderTest.class.getClassLoader();
        InputStream is = classLoader.getResourceAsStream("L2.properties");
        ps.load(is);


        String name = ps.getProperty("name");
        String password = ps.getProperty("password");
        System.out.println("name = "+name+" password = "+password);
4.

        1.创建运行时类的对象

//newInstance();调用此方法创建对应的运行时类的对象、内部调用了运行时类的空参构造器 // 要想此方法能正常创建运行时类的对象,要求: // 1.运行时类必须有空参构造器 // 2.访问权限要够。通常为public
// 在javabean中要求提供一个空参构造器。1,便于通过反射,创建运行时类的对象, // 2,便于子类继承父类时,默认调用super()时保证父类有此构造器

       Class<Person> clazz = Person.class;
        // Person o = clazz.newInstance();
        // 此方法已经被getDeclaredConstructor().newInstance();替代
        Person person = Person.class.getDeclaredConstructor().newInstance();
        System.out.println(person);

2.获取运行时类中的一些结构

————————————————————————————

获取构造器结构:
  public void test() {
        Class clazz = Person.class;
        //getConstructors()获取当前运行时类的所有public的构造器
        Constructor[] constructor = clazz.getConstructors();
        for (Constructor c: constructor) {
            System.out.println(c);
        }
        //getDeclaredConstructors()获取当前运行时类的所有的构造器
       
        Constructor[] constructors = clazz.getDeclaredConstructors();
        for (Constructor c: constructors) {
            System.out.println(c);
        }
  }

 //获取运行时类的父类
    @Test
    public void test2() {
        Class clazz = Person.class;
        Class superclass = clazz.getSuperclass();
        System.out.println(superclass);
        //获取带泛型的父类
        Type type = clazz.getGenericSuperclass();
        System.out.println(type);
    }

/*
    获取带泛型的父类的泛型
     */
  @Test
    public void test3() {
        Class clazz = Person.class;
        Type genericSuperclass = clazz.getGenericSuperclass();
        ParameterizedType parmeType = (ParameterizedType) genericSuperclass;
        //获取泛型类型
        Type[] actualTypeArguments = parmeType.getActualTypeArguments();
        System.out.println(((Class)actualTypeArguments[0]).getName());
    }


    ————————————————————

3.获取指定结构

  @Test
    public void test() throws Exception {
        //获取运行时类的对象
//        Person person = Person.class.getDeclaredConstructor().newInstance();
        Class aClass = Person.class;
        Person o = (Person) aClass.newInstance();
        //获取指定属性
        Field id = aClass.getField("age");
        //year获取静态属性
        Field year = aClass.getDeclaredField("year");
        /*
            设置当前属性的值
            set():参数1:指明设置那个对象的属性   参数2:将此属性值设置为多少
            setAccessible(true);保证当前属性是可访问的
         */

        year.setAccessible(true);
        year.set(null,2021);
        id.set(o,100111);

        /*
            获取当前属性的值
            get():参数1:获取那个对象的当前属性值
         */
        int o1 = (int) id.get(o);
        System.out.println(o1);
        System.out.println(year.get(null));

    }
    /*
    如何操作运行时类中的指定的属性*
     */
    @Test
    public void test2() throws Exception {
        Class personClass = Person.class;
        //获取运行时类的对象
        Object o = personClass.newInstance();
        //getDeclaredField(String fieldName):获取运行时类中指定变量名的属性
        Field field = personClass.getDeclaredField("sex");
        //确保当前属性时可访问的
        field.setAccessible(true);
        //获取,设置指定对象的此属性值
        field.set(o,"男");

        Object o1 = field.get(o);
        System.out.println(o1);
    }
    /*
     如何操作运行时类中的指定的方法*

     */
    @Test
    public void test3() throws Exception {
        Class personClass = Person.class;
        //获取运行时类的对象
        Person p = (Person) personClass.newInstance();
        /*
        获取指定的方法
        getDeclaredMethod(): 参数1 :获取指定方法的方法名  参数2:指定方法中的形参列表。
         */
        Method show = personClass.getDeclaredMethod("getCH", String.class);
        //保证当前的方法是可访问的
        show.setAccessible(true);
        /*
        调用invoke():参数1:方法的调用者(运行时类的对象),参数2给方法的形参赋值。
        invoke方法的返回值即为对应类中调用方法的返回值
         */
        Object invoke = show.invoke(p, "中国");
        System.out.println(invoke);
        System.out.println("———————————调用静态的方法———————————");
//        public static void LXD()

        Method lxd = personClass.getDeclaredMethod("LXD");
        lxd.setAccessible(true);
        //invoke()方法有一个返回值,如果调用的运行时类的方法中无返回值则返回null
//        Object invoke1 = lxd.invoke(Person.class);
        Object invoke1 = lxd.invoke(null);
        System.out.println(invoke1);//null

5。代理模式与动态代理

代理设计模式的原理:

使用一个代理将对象包装起来, 然后用该代理对象取代原始对象。任何对原始对象的调用都要通过代理。代理对象决定是否以及何时将方法调用转到原始对象上。

之前为大家讲解过代理机制的操作,属于静态代理,特征是代理类和目标对象的类都是在编译期间确定下来,不利于程序的扩展。同时,每一个代理类只能为一个接口服务,这样一来程序开发中必然产生过多的代理。最好可以通过一个代理类完成全部的代理功能

动态代理是指客户通过代理类来调用其它对象的方法,并且是在程序运行时根据需要动态创建目标类的代理对象。

动态代理使用场合:

调试
远程方法调用
动态代理相比于静态代理的优点:

抽象角色中(接口)声明的所有方法都被转移到调用处理器一个集中的方法中处理,这样,我们可以更加灵活和统一的处理众多的方法。

5.1静态代理举例:

interface ClothFactory {
    public void produceCloth();
}
//代理类
class ProxyClothFactory implements ClothFactory{
    private ClothFactory Cloth;

    public ProxyClothFactory(ClothFactory Cloth){
        this.Cloth = Cloth;
    }
    @Override
    public void produceCloth() {
        System.out.println("我是代理类做一些准备工作");
        Cloth.produceCloth();
        System.out.println("代理类完成了代理操作");
    }
}
//被代理类
class ProxyPerson implements ClothFactory{
    @Override
    public void produceCloth() {
        System.out.println("我是被代理类,");
    }


}
public class StaticDaiLiTest {
    public static void main(String[] args) {
        //创建被代理类对象
        ProxyPerson p = new ProxyPerson();
        //创建代理类对象
        ProxyClothFactory factory = new ProxyClothFactory(p);
        factory.produceCloth();

    }
}

        

5.2动态代理举例

package DaiLi;
/*
    动态代理

 */


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

interface Human{
    public String getBelief();
    void eat(String food);
}
//被代理类
class SuperMan implements Human{

    @Override
    public String getBelief() {
        return "我是No:1";
    }

    @Override
    public void eat(String food) {
        System.out.println("我喜欢吃"+food);
    }
}
/*
    要想实现动态代理,需要解决的问题?
    问题一:如何根据加载到内存中的被代理类,动态的创建一个代理类及其对象
    问题二:当通过代理类的对象调用方法A时,如何动态的去调用被代理类中的同名方法A。

 */

class ProxyFactory{
    //调用此方法,返回一个代理类的对象。解决问题一

    public static Object getProxyInstance(Object obj){//obj:被代理类的对象
        MyInvocationHandler handler = new MyInvocationHandler();

        handler.bind(obj);

        return Proxy.newProxyInstance(obj.getClass().getClassLoader(),obj.getClass().getInterfaces(),handler);
    }
}

class MyInvocationHandler implements InvocationHandler{

    private Object obj;//需要使用被代理的对象进行赋值
    public void bind(Object obj){
        this.obj = obj;
    }

    //当我们通过代理类的对象,调用方法a时,就会自动的调用如下的方法:invoke()
    //将被代理类要执行的方法a的功能就声明在invoke()中
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        //method:即为代理类对象调用的方法,此方法也作为了被代理类对象要调用的方法
        //obj:被代理类的对象
        Object returnValue = method.invoke(obj, args);
        //代理类方法的返回值就作为当前类中的invoke方法的返回值。
        return returnValue;


    }
}


public class RunDaiLiTest {
    public static void main(String[] args) {
        SuperMan sup = new SuperMan();
        //proxyInstance;代理类的对象
        Human proxyInstance = (Human) ProxyFactory.getProxyInstance(sup);
        //当通过代理类对象调用方法时,会自动调用被代理类中同名的方法
        System.out.println(proxyInstance.getBelief());
        proxyInstance.eat("西红柿");

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

        ProxyPerson proxyPerson = new ProxyPerson();
        ClothFactory proxyInstance1 = (ClothFactory) ProxyFactory.getProxyInstance(proxyPerson);
        proxyInstance1.produceCloth();
    }

}

5.3AOP

前面介绍的Proxy和InvocationHandler,很难看出这种动态代理的优势,下面介绍一种更实用的动态代理机制

 

  1.  改进后的说明:代码段1、代码段2、代码段3和深色代码段分离开了,但代码段1、2、3又和一个特定的方法A耦合了!最理想的效果是:代码块1、2、3既可以执行方法A,又无须在程序中以硬编码的方式直接调用深色代码的方法。
  2. 使用Proxy生成一个动态代理时,往往并不会凭空产生一个动态代理,这样没有太大的意义。通常都是为指定的目标对象生成动态代理
  3. 这种动态代理在AOP中被称为AOP代理,AOP代理可代替目标对象,AOP代理包含了目标对象的全部方法。但AOP代理中的方法与目标对象的方法存在差异:AOP代理里的方法可以在执行目标方法之前、之后插入一些通用处理

        图示

 实例一:

package DaiLi;
/*
    动态代理

 */


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

interface Human{
    public String getBelief();
    void eat(String food);
}
//被代理类
class SuperMan implements Human{

    @Override
    public String getBelief() {
        return "我是No:1";
    }

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

//动态代理AOP模式举例
class HumanUtil{
     public void method1(){
        System.out.println("——————————————————通用方法1——————————————————");
    }
    public void method2(){
        System.out.println("——————————————————通用方法2——————————————————");
    }
}


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

 */

class ProxyFactory{
    //调用此方法,返回一个代理类的对象。解决问题一

    public static Object getProxyInstance(Object obj){//obj:被代理类的对象
        MyInvocationHandler handler = new MyInvocationHandler();

        handler.bind(obj);

        return Proxy.newProxyInstance(obj.getClass().getClassLoader(),obj.getClass().getInterfaces(),handler);
    }
}

class MyInvocationHandler implements InvocationHandler{

    private Object obj;//需要使用被代理的对象进行赋值
    public void bind(Object obj){
        this.obj = obj;
    }

    //当我们通过代理类的对象,调用方法a时,就会自动的调用如下的方法:invoke()
    //将被代理类要执行的方法a的功能就声明在invoke()中
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //动态代理AOP模式举例
        HumanUtil hum = new HumanUtil();
        hum.method1();

        //method:即为代理类对象调用的方法,此方法也作为了被代理类对象要调用的方法
        //obj:被代理类的对象
        Object returnValue = method.invoke(obj, args);


        //动态代理AOP模式举例
        hum.method2();

        //代理类方法的返回值就作为当前类中的invoke方法的返回值。
        return returnValue;


    }
}


public class RunDaiLiTest {
    public static void main(String[] args) {
        SuperMan sup = new SuperMan();
        //proxyInstance;代理类的对象
        Human proxyInstance = (Human) ProxyFactory.getProxyInstance(sup);
        //当通过代理类对象调用方法时,会自动调用被代理类中同名的方法
        System.out.println(proxyInstance.getBelief());
        proxyInstance.eat("西红柿");

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

        ProxyPerson proxyPerson = new ProxyPerson();
        ClothFactory proxyInstance1 = (ClothFactory) ProxyFactory.getProxyInstance(proxyPerson);
        proxyInstance1.produceCloth();
    }

}

猜你喜欢

转载自blog.csdn.net/asdascca/article/details/121527381