02_基础加强_其他

反射

概述

反射是指对于任何一个Class类,在"运行的时候"都可以直接得到这个类全部成分。

在运行时,可以直接得到这个类的:

  • 构造器对象:Constructor

  • 成员变量对象:Field

  • 成员方法对象:Method

这种运行时动态获取类信息以及动态调用类中成分的能力称为Java语言的反射机制。

用法

  1. 获取类的Class对象

    • Class.forName(<全类名>)
    • 类名.class
    • 对象.getClass
  2. 获取构造器

    方法 说明
    Constructor<?>[] getConstructors() 返回所有构造器对象的数组(只能拿public的)
    Constructor<?>[] getDeclaredConstructors() 返回所有构造器对象的数组,存在就能拿到
    Constructor getConstructor(Class<?>... parameterTypes) 返回单个构造器对象(只能拿public的)
    Constructor getDeclaredConstructor(Class<?>... parameterTypes) 返回单个构造器对象,存在就能拿到

    构造器类常用方法:

    符号 说明
    T newInstance(Object... initargs) 根据指定的构造器创建对象
    public void setAccessible(boolean flag) 设置为true,表示取消访问检查,进行暴力反射
  3. 获取成员变量

    方法 说明
    Field[] getFields() 返回所有成员变量对象的数组(只能拿public的)
    Field[] getDeclaredFields() 返回所有成员变量对象的数组,存在就能拿到
    Field getField(String name) 返回单个成员变量对象(只能拿public的)
    Field getDeclaredField(String name) 返回单个成员变量对象,存在就能拿到

    Field常用方法:

    符号 说明
    void set(Object obj, Object value): 赋值
    Object get(Object obj) 获取值。
  4. 获取成员方法

    方法 说明
    Method[] getMethods() 返回所有成员方法对象的数组(只能拿public的)
    Method[] getDeclaredMethods() 返回所有成员方法对象的数组,存在就能拿到
    Method getMethod(String name, Class<?>... parameterTypes) 返回单个成员方法对象(只能拿public的)
    Method getDeclaredMethod(String name, Class<?>... parameterTypes) 返回单个成员方法对象,存在就能拿到

    Method常用方法:

    符号 说明
    Object invoke(Object obj, Object... args) 运行方法 参数一:用obj对象调用该方法 参数二:调用方法的传递的参数(如果没有就不写) 返回值:方法的返回值(如果没有就不写)

作用

  1. 绕过编译阶段为集合添加数据

    反射是作用在运行时的技术,此时集合的泛型将不能产生约束了,此时是可以为集合存入其他任意类型的元素的。

    ArrayList<Integer> list = new ArrayList<>();
    list.add(100);
    list.add(“黑马"); // 报错,但通过反射添加则不会
    

    泛型只是在编译阶段可以约束集合只能操作某种数据类型,在编译成Class文件进入运行阶段的时候,其真实类型都是ArrayList了,泛型相当于被擦除了。

  2. 通用框架底层

    如不同类的对象都解析出成员变量名及值并存入日志。

注解

概述

Java 注解(Annotation)又称 Java 标注,是 JDK5.0 引入的一种注释机制。

范围:类、构造器、方法、成员变量、参数等。

作用:对Java中类、方法、成员变量做标记,然后进行特殊处理,至于到底做何种处理由业务需求来决定。
例如:JUnit框架中,标记了注解@Test的方法就可以被当成测试方法执行,而没有标记的就不能当成测试方法执行。

用法

定义:

public @interface 注解名称 {
    public 属性类型 属性名() default 默认值 ;
}

解析:注解的解析就是判断是否存在注解,存在注解就解析出内容。

相关接口:

  • Annotation: 注解的顶级接口,注解都是Annotation类型的对象

  • AnnotatedElement:该接口定义了与注解解析相关的解析方法

常用方法:

方法 说明
Annotation[] getDeclaredAnnotations() 获得当前对象上使用的所有注解,返回注解数组。
T getDeclaredAnnotation(Class annotationClass) 根据注解类型获得对应注解对象
boolean isAnnotationPresent(Class annotationClass) 判断当前对象是否使用了指定的注解,如果使用了则返回true,否则false

所有的类成分Class, Method , Field , Constructor,都实现了AnnotatedElement接口他们都拥有解析注解的能力。

元注解

给注解添加注解的注解~

有2个:

  • @Target: 约束自定义注解只能在哪些地方使用。

    可使用的值定义在ElementType枚举类中,常用值如下:

    • TYPE,类,接口

    • FIELD, 成员变量

    • METHOD, 成员方法

    • PARAMETER, 方法参数

    • CONSTRUCTOR, 构造器

    • LOCAL_VARIABLE, 局部变量

  • @Retention:申明注解的生命周期。

    可使用的值定义在RetentionPolicy枚举类中,常用值如下:

    • SOURCE: 注解只作用在源码阶段,生成的字节码文件中不存在

    • CLASS: 注解作用在源码阶段,字节码文件阶段,运行阶段不存在,默认值.

    • RUNTIME:注解作用在源码阶段,字节码文件阶段,运行阶段(开发常用)

动态代理

概述

代理就是被代理者没有能力或者不愿意去完成某件事情,需要找个人代替自己去完成这件事,动态代理就是用来对业务功能(方法)进行代理的。

比如每个业务方法都要计算耗时,如果在方法里自己计算,则会出现代码重复,使用代理可以优雅地解决。

实现的关键:

  • 必须有接口,实现类要实现接口(代理通常是基于接口实现的)。

  • 创建一个实现类的对象,该对象为业务对象,紧接着为业务对象做一个代理对象。

优点:

  • 非常的灵活,支持任意接口类型的实现类对象做代理,也可以直接为接本身做代理。

  • 可以为被代理对象的所有方法做代理。

  • 可以在不改变方法源码的情况下,实现对方法功能的增强。

  • 不仅简化了编程工作、提高了软件系统的可扩展性,同时也提高了开发效率。

用法

创建通用代理工具类

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

public class ProxyUtil {
    static <T> T getUserProxy(T object) {
        return (T) Proxy.newProxyInstance(object.getClass().getClassLoader(), object.getClass().getInterfaces(), new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                long startTime = System.currentTimeMillis();

                Object result = method.invoke(object, args);

                System.out.println(method.getName() + " ran for " + (System.currentTimeMillis() - startTime) / 1000.0 + "s");

                return result;
            }
        });
    }
}

创建业务对象并调用:

public class ProxyTest {
    public static void main(String[] args) {
        User user = ProxyUtil.getUserProxy(new UserImpl());
        user.login();
        user.update();
        user.delete();
    }
}

输出:
image-20230422185828911

posted @ 2023-07-06 17:11  水木夏  阅读(2)  评论(0编辑  收藏  举报