注解与反射

1、注解(Annotation


1.1、何为注解?

注解(Annotation)是从JDK5.0开始引入的技术,以@注解名在代码中存在,例如:

  • @Override:限定重写父类方法,该注解只能用于方法
  • @Deprecated:用于表示所修饰的元素(类,方法)已过时
  • @SuppressWarnings:抑制编译器警告(镇压警告)

Annotation可以像修饰符一样被使用,可用于修饰包、类、构造器、成员变量、参数、局部变量的声明,还可添加一些参数值

1.2、注解与注释

注解也可以看做是一种注释,通过使用Annotation,程序员可以在不改变原有逻辑的情况下,在源文件中嵌入一些补充信息。但是,注解,不同于单行注释和多行注释

  • 对于单行注释和多行注释是给程序员看的
  • 而注解是可以被编译器或其他程序读取的。程序还可以根据注解的不同,做出相应的处理

10.3、注解的重要性

在JavaSE中,注解的使用目的比较简单,例如标记过时的功能,忽略警告等。在JavaEE/Android中注解占据了更重要的角色,例如用来配置应用程序的任何切面,代替JavaEE旧版中所遗留的繁冗代码和XML配置

注解是大势所趋,框架 = 注解 + 反射 + 设计模式

10.4、自定义注解

public @interface MyAnnotation {
    String value() default "hello world";
}

特殊属性

  • value属性,如果只有一个value属性的情况下,使用value属性的时候可以省略value名称不写
  • 但是如果有多个属性,且多个属性没有默认值,那么value名称是不能省略的

10.5、元注解

元注解:对现有的注解进行解释说明的注解

  • Target:约束自定义注解只能在哪些地方使用
  • Retention:申明注解的生命周期
  • Documented:表示所修饰的注解在被javadoc解析时,保留下来
  • Inherited:被它修饰的Annotation将具备继承性
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, MODULE, PARAMETER, TYPE})
public @interface MyAnnotation {
    String value() default "hello world";
}

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

  • TYPE:类,接口
  • FIELD:成员变量
  • METHOD:成员方法
  • PARAMETER:方法参数
  • CONSTRUCTOR:构造器
  • LOCAL_VARIABLE:局部变量

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

  • SOURCE: 注解只作用在源码阶段,生成的字节码文件中不存在
  • CLASS: 注解作用在源码阶段,字节码文件阶段,运行阶段不存在,默认值
  • RUNTIME:注解作用在源码阶段,字节码文件阶段,运行阶段(开发常用)

2、反射(reflection


2.1、何为反射?

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

在运行时,可以直接得到这个类的构造器对象:Constructor

在运行时,可以直接得到这个类的成员变量对象:Field

在运行时,可以直接得到这个类的成员方法对象:Method

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

反射的关键:反射的第一步都是先得到编译后的Class类对象,然后就可以得到Class的全部成分

反射的作用:

  • 获取一个类里面所有的信息,获取到了之后,再执行其他的业务逻辑
  • 结合配置文件,动态的创建对象并调用其方法

2.2、获取class对象三种方式

在这里插入图片描述

public static void main(String[] args) throws ClassNotFoundException {
    // 全类名 = 包名 + 类名
    // 第一种方式:最为常用
    Class clazz1 = Class.forName("com.zhang.Student");
    System.out.println(clazz1);

    // 第二种方式:一般当做参数传递
    Class<Student> clazz2 = Student.class;

    // 第三种方式:必须有了该类之后,才可获取使用
    Student stu = new Student();
    Class<? extends Student> clazz3 = stu.getClass();
    System.out.println(clazz1 == clazz2);       // true
    System.out.println(clazz2 == clazz3);       // true
}

2.3、反射获取构造方法

获取构造器的方法

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

Constructor类中用于创建对象的方法

符号说明
T newInstance(Object… initargs)根据指定的构造器创建对象
public void setAccessible(boolean flag)设置为true,表示取消访问检查,进行暴力反射
public static void main(String[] args) throws Exception {
    // 获取字节码文件的对象
    Class<?> clazz = Class.forName("com.zhang.Student");
    // 获取所有公共的构造方法
    /* Constructor<?>[] cons = clazz.getConstructors();
    for (Constructor<?> con : cons) {
        System.out.println(con);
    } */

    // 获取所有的构造方法(包括私有)
    /* Constructor<?>[] dc = clazz.getDeclaredConstructors();
    for (Constructor<?> d : dc) {
        System.out.println(d);
    } */

    // 获取空参构造
    Constructor con1 = clazz.getDeclaredConstructor();
    System.out.println(con1);

    // 获取一个参数的构造(参数类型是String的)
    Constructor<?> con2 = clazz.getDeclaredConstructor(String.class);
    System.out.println(con2);

    // 获取二个参数的构造(参数类型是String、int的)
    Constructor<?> con3 = clazz.getConstructor(String.class, int.class);
    System.out.println(con3);

    // 临时取消权限校验(暴力反射)
    con2.setAccessible(true);
    Student stu = (Student) con2.newInstance("小昭");
    System.out.println(stu);
}

2.4、反射获取成员变量

public static void main(String[] args) throws Exception {
    // 获取字节码文件的对象
    Class<?> clazz = Class.forName("com.zhang.Student");
    // 获取所有公共的成员变量
    /* Field[] fields = clazz.getFields();
    for (Field field : fields) {
        System.out.println(field);
    } */

    // 获取所有成员变量(包括私有)
    /* Field[] dfs = clazz.getDeclaredFields();
    for (Field field : dfs) {
        System.out.println(field);
    } */

    // 获取指定的成员变量(公共的)
    Field address = clazz.getField("address");
    System.out.println(address);

    // 获取指定的成员变量(公共私有)
    Field name = clazz.getDeclaredField("name");
    System.out.println(name.getName());

    // 获取成员变量的类型
    System.out.println(name.getType());

    Student s1 = new Student("小黑", 22, "河南-郑州");

    // 暴力反射
    name.setAccessible(true);
    // 获取成员变量的值
    String value = (String) name.get(s1);
    System.out.println(value);

    // 修改对象中的值
    name.set(s1, "小白");

    System.out.println(s1);
}

2.5、反射获取成员方法

public static void main(String[] args) throws Exception {
    Class<?> clazz = Class.forName("com.zhang.Student");
    // 获取所有公共的成员方法(包括父类)
    // Method[] methods = clazz.getMethods();
    // for (Method method : methods) {
    //     System.out.println(method);
    // }

    // 获取所有成员方法(包括本类私有,不包括父类)
    // Method[] dm = clazz.getDeclaredMethods();
    // for (Method method : dm) {
    //     System.out.println(method);
    // }

    // 获取指定成员方法(公共的)
    Method getName = clazz.getMethod("getName");
    System.out.println(getName);

    // 获取指定成员方法(公共私有)
    Method hello = clazz.getDeclaredMethod("sayHello", String.class);
    System.out.println(hello);

    // 获取方法名
    System.out.println(hello.getName());        // sayHello

    // 获取方法参数个数
    System.out.println(hello.getParameterCount());      // 1

    // 获取方法抛出的异常
    Class<?>[] ets = hello.getExceptionTypes();
    for (Class<?> ex : ets) {
        System.out.println(ex);
    }

    // 调用成员方法
    // 暴力反射
    hello.setAccessible(true);
    Student s1 = new Student("晓琳", 22, "北京-海淀");
    String res = (String) hello.invoke(s1, s1.getName());
    System.out.println(res);

    // 获取方法的返回值
    System.out.println(hello.getReturnType());      // java.lang.String
}

3、动态代理


3.1、什么是动态代理?

特点:无侵入式的给代码增加额外的功能

代理就是被代理者没有能力或者不愿意去完成某件事情,需要找个人代替自己去完成这件事

代理关键步骤

  • 必须有接口,实现类要实现接口(代理通常是基于接口实现的)
  • 创建一个实现类的对象,该对象为业务对象,紧接着为业务对象做一个代理对象

UserService

public interface UserService {
    ArrayList<User> queryUser() throws InterruptedException;

    void delUser(String username) throws InterruptedException;

    void addUser(User user) throws InterruptedException;
}

UserServiceImpl

public class UserServiceImpl implements UserService {
    private static ArrayList<User> users = new ArrayList<>();

    static {
        users.add(new User("小白", "666666", "xiaobai@qq.com", 25));
        users.add(new User("小昭", "123456", "xiaozhao@163.com", 22));
        users.add(new User("夏琳", "666666", "xialin@qq.com", 22));
    }

    @Override
    public ArrayList<User> queryUser() throws InterruptedException {
        Thread.sleep(1000);
        return users;
    }

    @Override
    public void delUser(String username) throws InterruptedException {
        for (int i = 0; i < users.size(); i++) {
            User user = users.get(i);
            if (user.getUserName().equals(username)) {
                users.remove(user);
                System.out.println("删除成功");
            }
        }
        Thread.sleep(2000);
    }

    @Override
    public void addUser(User user) throws InterruptedException {
        users.add(user);

        Thread.sleep(1500);
    }
}

ProxyTool

public class ProxyTool {
    public static UserService createProxy(UserService userService) {
        UserService UserService = (UserService) Proxy.newProxyInstance(
                ProxyTool.class.getClassLoader(),
                new Class[]{UserService.class},
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        String methodName = method.getName();
                        if ("addUser".equals(methodName) || "delUser".equals(methodName) || "queryUser".equals(methodName)) {
                            // 添加测试代码执行时长
                            long start = System.currentTimeMillis();
                            
                            Object result = method.invoke(userService, args);
                            
                            long end = System.currentTimeMillis();
                            
                            System.out.println(methodName + "执行耗时:" + (end - start) / 1000.0 + "秒");
                            return method.invoke(userService, args);
                        } else {
                            return method.invoke(userService, args);
                        }
                    }
                }
        );
        return UserService;
    }
}

Test

public class TestUserService {
    public static void main(String[] args) throws InterruptedException {
        // 创建用户业务对象
        UserService userService = new UserServiceImpl();
        UserService proxy = ProxyTool.createProxy(userService);

        // 调用对应业务功能
        proxy.addUser(new User("小黑", "888888", "xiaohei@163.com", 26));
        System.out.println("=========================");

        proxy.delUser("小昭");
        System.out.println("=========================");

        ArrayList<User> users = proxy.queryUser();
        for (User user : users) {
            System.out.println(user);
        }
        System.out.println("=========================");
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值