java-反射复习

一、概述

       如何在运行时识别一个对象的类型和所属类的信息,一种是假设在编译时已经知道了所有的类型,也就是程序员写的"正向"的代码,一种是反射机制

       反射就是把java类中的各种成分(成员变量、方法、构造方法、包)进行解剖,映射成一个个的Java对象

       类加载完之后,在堆内存的方法区中会产生一个Class类型的对象(一个类只有一个Class对象),这个对象包含了完整的类的结构信息

这个对象像一面镜子,透过这个镜子可以看到类的结构,形象称之为反射。

      反射机制提供的功能:

(1)在运行时判断任意一个对象所属的类

(2)在运行时构造任意一个类的对象

(3)在运行时判断任意一个类所具有的成员变量和方法

(4)在运行时获取泛型信息

(5)在运行时调用任意一个对象的成员变量和方法

(6)在运行时处理注解

(7)生成动态代理

     主要API:

java.lang.Class,用来描述类的类

java.lang.reflect.Method

java.lang.reflect.Field

java.lang.reflect.Constructor

二、Class类和其实例

 

三、类加载和ClassLoader

AppClassLoader加载自定义的类,也就是程序员写的类(System ClassLoader)

ExtClassLoader,负责加载jre/lib/ext目录下的jar (Extension ClassLoader)

BootstrapClassLoader,C++编写,是JVM自带的类加载器,负责java平台核心类库的类加载,无法直接获取(getParent()获取是null)

//自定义类,使用system classLoader
ClassLoader classLoader = ClassLoaderTest.class.getClassLoader();
System.out.println(classLoader);//sun.misc.Launcher$AppClassLoader@18b4aac2
//system classLoader的父加载器是扩展类加载器
ClassLoader classLoader1 = classLoader.getParent();
System.out.println(classLoader1);//sun.misc.Launcher$ExtClassLoader@255316f2
//扩展类加载器的父加载器是根加载器,根加载器无法获取,结果是null
ClassLoader classLoader2 = classLoader1.getParent();
System.out.println(classLoader2);//null
//根加载器加载java核心类库,不能加载自定义的类
ClassLoader classLoader3 = String.class.getClassLoader();
System.out.println(classLoader3);//null

四、创建运行时类的Class对象

获取某个类的Class对象的四种方式:

  • 根据类名:类名.class
  • 根据对象:对象.getClass()
  • 根据全限定类名:Class.forName(全限定类名)
  • 类加载器加载:ClassLoder.loadClass(全限定类名)
public void classTest() throws Exception {
        // 获取Class对象的四种方式
        Class clazz1 = User.class;
        Class clazz2 = new User().getClass();
        Class clazz3 = Class.forName("com.test.User");

        ClassLoader classLoader = Test.class.getClassLoader();
        Class clazz4 = classLoader.loadClass("com.test.User");

        System.out.pirntln(clazz1==clazz2);  //true
        System.out.pirntln(clazz1==clazz3);  //true
        System.out.pirntln(clazz1==clazz4);  //true
}

注意:以上四种方式获取User的Class实例都是同一份,都相同

五、获取和调用运行时类的完整结构

//getFields();获取当前运行时类及其父类中声明为public权限的属性
//getDeclaredFields();获取当前运行时类自己声明的属性(不包含父类中的)
//getDeclaredField(String fieldName) 获取指定名的属性
//setAccessible(true)--设置属性可访问
//getMethods();获取当前运行时类及其父类中声明为public权限的方法
//getDeclaredMethods();获取当前运行时类自己声明的方法
//getDeclaredMethod(String methodName,Class parameterType...)
//Method.invoke()---返回Object类型,没有返回值则返回null
//getDeclaredConstructor()----constructor.newInstance()---创建一个对象

六、反射的典型应用:动态代理

静态代理:代理类和代理的目标类(被代理的类)事先是知道的

动态代理:客户端仍然通过代理类调用被代理类的方法,但是代理类是在程序运行时根据需要动态创建代理对象

JDK动态代理的关键类:Proxy,InvocationHandler

public interface Human {
    void eat(String food);
    void work();
}

/**
 * 被代理类,实现相同的接口
 */
public class Teacher implements Human{
    @Override
    public void eat(String food) {
        System.out.println("====老师在吃"+food+"=====");
    }

    @Override
    public void work() {
        System.out.println("====老师的工作是教书");
    }
}

package com.yb.designpattern.proxy.dynamic;

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

public class MyInvocationHandler implements InvocationHandler {

    /**
     * 被代理类的对象
     */
    private Object obj;

    public MyInvocationHandler(Object obj) {
        this.obj = obj;
    }

    /**
     * 当通过代理类的对象调用方法时,会自动调用如下方法
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("前置处理逻辑");
        Object returnValue = method.invoke(obj, args);
        System.out.println("后置处理逻辑");
        return returnValue;
    }
}

package com.yb.designpattern.proxy.dynamic;

import java.lang.reflect.Proxy;

public class ProxyFactory {

    /**
     * 输入被代理类的对象,返回其代理类的对象
     *
     * @param obj 被代理的类的对象
     * @return 它的代理类的对象
     */
    public static Object getProxyInstance(Object obj) {
        MyInvocationHandler invocationHandler = new MyInvocationHandler(obj);
        Object o = Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), invocationHandler);
        return o;
    }
}


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

    public static void main(String[] args) {
        Teacher teacher = new Teacher();
        Human proxyInstance = (Human) 
        ProxyFactory.getProxyInstance(teacher);
        proxyInstance.eat("面包");
        proxyInstance.work();
    }
}

 

posted @ 2022-12-04 22:40  鼠标的博客  阅读(53)  评论(0编辑  收藏  举报