0%

注解和反射

1、注解

1.1、 内置注解

  • @Deprecated

    被注解的元素是不鼓励使用的程序元素,通常是因为它是危险的,或者因为存在更好的替代方法。

  • @Override

    表示重写父类方法。

  • @SuppressWarning

    抑制警告。

  • @FunctionaInterface

    指定接口必须为函数式接口。

1.2、元注解

元注解的作用就是负责注解其它注解。

  • @Target

    用于描述注解的使用范围。

  • @Retention

    表示需要在什么级别保存该注释信息,用于描述注解的生命周期。

    • SOURCE < CLASS < RUNTIME
  • @Document

    说明该注解将被包含在 javadoc 中。

  • @Inherited

    说明子类可以继承父类中的该注释。

1.3、自定义注解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import java.lang.annotation.*;

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@interface MyAnnotation1{
int age();
String[] hobby() default {"dance", "sing"};
}

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation2{
String value();
}

注解中的参数一定要加()

当注解只有一个参数时,参数名可以定义为 value,在调用的时候直接赋值就行。

1
2
3
4
5
public class MyAnnotationTest {
@MyAnnotation1(age = 12)
@MyAnnotation2("value")
String name;
}

2、反射

Java 反射就是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性,并且能改变它的属性。

2.1、获取 Class 类的实例

  • 通过类的 class 属性获取,安全可靠,性能最高。

    Class clz = Person.class;

  • 调用实例的 getClass() 方法。

    Class clz = person.getClass();

  • 通过 Class.forName() 获取。

    Class clz = Class.forName("com.yqx.Person");

1
2
3
4
5
6
7
8
@Test
public void test1() throws ClassNotFoundException {
Class clz1 = Person.class;
Class clz2 = new Person().getClass();
Class clz3 = Class.forName("Person");
System.out.println(clz1 == clz2); // true
System.out.println(clz2 == clz3); // true
}

2.2、拥有 Class 对象的类型

  • class:外部类,成员,局部内部类,匿名内部类。
  • interface:接口
  • []:数组
  • enum:枚举
  • annotation:注解 @interface
  • primitive type:基本数据类型
  • void
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
@Test
public void test2(){
Class clz1 = Object.class;
Class clz2 = Comparable.class;
Class clz3 = String[].class;
Class clz4 = String[][].class;
Class clz5 = Override.class;
Class clz6 = ElementType.class;
Class clz7 = Integer.class;
Class clz8 = void.class;
Class clz9 = Class.class;

System.out.println(clz1);
System.out.println(clz2);
System.out.println(clz3);
System.out.println(clz4);
System.out.println(clz5);
System.out.println(clz6);
System.out.println(clz7);
System.out.println(clz8);
System.out.println(clz9);

int[] a = new int[10];
int[] b = new int[100];
System.out.println(a.getClass() == b.getClass());
}

打印输出 (数组即使长度不同,其 Class 类也都是相同的)

1
2
3
4
5
6
7
8
9
10
11
12
class java.lang.Object
interface java.lang.Comparable
class [Ljava.lang.String;
class [[Ljava.lang.String;
interface java.lang.Override
class java.lang.annotation.ElementType
class java.lang.Integer
void
class java.lang.Class
true

Process finished with exit code 0

2.3、类的加载

2.4、获取类的属性及方法

反射机制允许程序在运行时取得任何一个已知名称的 class 的内部信息,包括包括其modifiers (修饰符),fields (属性),methods (方法)等,并可于运行时改变 fields 内容或调用 methods。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
@Test
public void test3() throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
// 获取 Class 对象
Class c1 = Class.forName("Person");

// 创建对象(无参)
Person person1 = (Person) c1.newInstance();
System.out.println(person1);

// 通过构造器创建对象
Constructor constructor = c1.getDeclaredConstructor(String.class, int.class);
Person person2 = (Person) constructor.newInstance("yqx", 20);
System.out.println(person2);

// 反射调用方法
Method method1 = c1.getDeclaredMethod("getName");
Method method2 = c1.getDeclaredMethod("setName", String.class);
String name1 = (String) method1.invoke(person1);
method2.invoke(person1, "deflory");
String name2 = (String) method1.invoke(person1);
System.out.println("Before: " + name1);
System.out.println("After: " + name2);

// 反射操作属性
Field field = c1.getDeclaredField("age");
field.setAccessible(true); // 设置可访问的
field.set(person1, 18);
System.out.println(person1.getAge());
}

打印内容

1
2
3
4
5
6
7
Person{name='null', age=0}
Person{name='yqx', age=20}
Before: null
After: deflory
18

Process finished with exit code 0

2.5、性能测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
@Test
public void test4() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
// 普通方法
Person person = new Person();
long start = System.currentTimeMillis();
for(int i=0;i<1e9;i++){
person.getAge();
}
long end = System.currentTimeMillis();
System.out.println("普通方法用时:" + (end - start) + "ms");

// 反射(检测开启)
Method method = Person.class.getDeclaredMethod("getAge");
start = System.currentTimeMillis();
for(int i=0;i<1e9;i++){
method.invoke(person);
}
end = System.currentTimeMillis();
System.out.println("反射(检测开启)用时:" + (end - start) + "ms");

// 反射(检测关闭)
method.setAccessible(true);
start = System.currentTimeMillis();
for(int i=0;i<1e9;i++){
method.invoke(person);
}
end = System.currentTimeMillis();
System.out.println("反射(检测关闭)用时:" + (end - start) + "ms");
}

打印内容

1
2
3
4
5
普通方法用时:1379ms
反射(检测开启)用时:1863ms
反射(检测关闭)用时:1591ms

Process finished with exit code 0

2.6、反射操作泛型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
@Test
public void test5() throws NoSuchMethodException {
Method test01 = Person.class.getDeclaredMethod("test01", Map.class, List.class);
Method test02 = Person.class.getDeclaredMethod("test02");

System.out.println("test01(参数泛型)");
Type[] genericParameterTypes = test01.getGenericParameterTypes();
for(Type genericParameterType : genericParameterTypes){
System.out.println(genericParameterType);
if (genericParameterType instanceof ParameterizedType){
Type[] actualTypeArguments = ((ParameterizedType) genericParameterType).getActualTypeArguments();
for(Type actualTypeArgument : actualTypeArguments){
System.out.println(actualTypeArgument);
}
}
}

System.out.println("\ntest02(返回值泛型)");
Type getGenericReturnType = test02.getGenericReturnType();
System.out.println(getGenericReturnType);
if (getGenericReturnType instanceof ParameterizedType){
Type[] actualTypeArguments = ((ParameterizedType) getGenericReturnType).getActualTypeArguments();
for(Type actualTypeArgument : actualTypeArguments){
System.out.println(actualTypeArgument);
}
}
}

打印内容

1
2
3
4
5
6
7
8
9
10
11
12
13
test01(参数泛型)
java.util.Map<java.lang.String, java.lang.Integer>
class java.lang.String
class java.lang.Integer
java.util.List<java.lang.Character>
class java.lang.Character

test02(返回值泛型)
java.util.Map<java.lang.String, java.lang.Integer>
class java.lang.String
class java.lang.Integer

Process finished with exit code