嚎羸的博客

因为Hexo是静态博客,部署多有不便,建议查看我的语雀文档

0%

13、注解与反射

反射

反射概述

反射,框架设计的灵魂所在

我们知道,Java代码在计算机会经过三个阶段:源代码、字节码、运行

其中,在编译对象之前,我们的Java程序需要经过一个叫做Class类对象的阶段,在这个阶段中,变量被封装为Field[],构造方法被封装为Constructor[],成员方法被封装为Method[]

也就是在字节码中,我们可以看到Filed[]Constructor[]Method[]

反射基本概念

反射获取Class对象有几种方式:

1、Class.forName("全类名"):将字节码文件加载到内存,存到Class对象

2、类名.class:通过类名的属性class获取

3、对象.getClass():Object中存在这个方法,所以这个方法在任何的对象中都能使用

Class对象有如下功能:

1、获取成员变量

1
2
3
4
5
6
7
8
// 获取所有public修饰的成员变量
demoClass.getFields();
// 获取指定名称修饰的public成员变量
demoClass.getField("");
// 获取所有的成员变量,包括私有的
demoClass.getDeclaredFields();
// 获取指定的成员变量,包括私有的
demoClass.getDeclaredField("");

2、获取构造方法

1
2
3
4
5
6
7
8
// 获取public构造方法们
demoClass.getConstructors();
// 获得有指定类型参数的public构造方法
demoClass.getConstructor(String.class);
// 获得构造方法们
demoClass.getDeclaredConstructors();
// 获得指定参数的构造方法
demoClass.getDeclaredConstructor(String.class);

3、获取成员方法

1
2
3
4
5
6
7
8
// 获取全部public方法
demoClass.getMethods();
// 获取指定名称,并且参数匹配的public方法,参数可以不写,可以写多个
demoClass.getMethod("",String.class);
// 获取全部方法
demoClass.getDeclaredMethods();
// 获取指定名称,并且参数匹配的方法,参数可以不写,可以写多个
demoClass.getDeclaredMethod("",String.class);

4、获取全类名

1
demoClass.getName()

Field有如下功能:

1、获取和设置值

1
2
3
4
// 获取值 
Object o = fields[0].get(Object o);
// 设置值
fields[0].set(Object o, Object o1);

2、忽略访问权限修饰符的安全检查

1
2
// 这种形式我们称为暴力反射
fields[0].setAccessible(true);

Constructor有如下功能:

1、创建对象

1
2
3
4
5
Class<DynamicLinkDemo> demoClass = DynamicLinkDemo.class;

Constructor<DynamicLinkDemo> demoConstructor = demoClass.getConstructor(String.class);
// 创建对象。使用空参构造可以不用传递参数
DynamicLinkDemo demo = demoClass.newInstance("");

Method有如下功能:

1、获取方法名称

1
2
3
4
5
Class<DynamicLinkDemo> demoClass = DynamicLinkDemo.class;

Method method = demoClass.getMethod("A");
// 获取名称
String name = method.getName();

2、执行方法

1
2
3
4
5
6
7
Class<DynamicLinkDemo> demoClass = DynamicLinkDemo.class;

DynamicLinkDemo newInstance = demoClass.getConstructor().newInstance();

Method method = demoClass.getMethod("A");
// 执行方法,给出对象和对应的方法
method.invoke(newInstance,method);

注解

注解概述

注解:Annotation:也就是说给计算机看的,使用的时候使用@注解名称

它在JDK5引入的一个新的特性,和类、接口、枚举在一个层面上。它可以声明在任意的类、方法、变量上,用来对这些元素进行说明和注释

注解可以通过反射读取到,那么这样就可以在调用方法之前或之后,进行方法的增强

注解基本概念

JDK中有一些预定义的注解:

1、@Override:检测被该注解标注的方法是否是继承自父类接口的,当然不加也没有关系,这个注解主要是检查是否合乎规范的

2、Deprecate:表示当前的内容已经过时

3、@SuppressWarnings:压制警告

这个注解假如加到类上的时候,说明要压制类上的警告,方法同理

这个需要传递参数,一般传递all,这样全部的警告都不会出现:@SuppressWarning("all")

自定义注解

自定义注解的格式分两种:

1、元注解

2、public @interface 注解名称

先说我们一般的注解

它要使用@来声明,声明的时候使用@interface,注意不是大写I

注解类里面的抽象方法需要几个要求:

1、返回值有如下取值:

  • 基本数据类型
  • String
  • 枚举
  • 其他注解
  • 以上几个类型的数组

2、使用的时候,需要赋值

假如我们在定义抽象方法的时候,假如使用default关键字给一个默认的初始化值,那么则使用注解的时候,可以不进行赋值,否则必须赋值

假如只有一个需要赋值,并且属性的名字是value,那么value可以省略,直接定义值即可

数组赋值时,需要使用{}包裹,假如数组中只有一个值,那么{}可以省略

光说不练假把式,上代码:

1
2
3
4
5
6
7
8
9
10
package com.howling;

public @interface AnnotationDemo {

public String name() default "Jerry";

public int age() default 22;

int[] value();
}
1
2
3
4
5
6
7
8
@AnnotationDemo(name = "Tom", age = 12, value = {23, 21})
String demo;

@AnnotationDemo(name = "Jack", value = 21)
String demo2;

@AnnotationDemo(21)
String demo3;

demo中,可以看到标准的赋值

demo2中,可以看到age因为有一个default,所以省略了,那么省略之后,默认的值就是22。value假如设置一个值,就不需要{}

demo3中,可以看到name也省略了,然而因为是value所以可以省略

元注解

元注解,描述注解的注解。这样说话可能有点绕,但是它确实用于确立注解的规则

1、@Target:描述注解可以作用的位置,使用ElementType取值

  • TYPE:类上
  • METHOD:方法上
  • FIELD:成员变量上

2、@Retention:描述注解被保留的阶段,一般我们使用RUNTIME,这样就会保留到字节码阶段,可以被JVM读取到

3、@Documented:描述注解是否可以被抽取到API中

4、@Inherited:描述注解是否可以被子类继承,只要有一个父类加上这个注解,那么它的子类全部都会继承这个注解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package com.howling;

import java.lang.annotation.*;

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface AnnotationDemo {

public String name() default "Jerry";

public int age() default 22;

int[] value();
}

反射获取注解

使用getAnnotation(Class)可以获取指定的注解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package com.howling.dynamiclink;

import com.howling.AnnotationDemo;

@AnnotationDemo(12)
public class DynamicLinkDemo {

public static void main(String[] args) {

Class<DynamicLinkDemo> demoClass = DynamicLinkDemo.class;

AnnotationDemo annotation = demoClass.getAnnotation(AnnotationDemo.class);

if (annotation == null) {
System.out.println("null");
} else {
System.out.println("not null");
}
}
}