Java注解与反射

说不上技术分享,只能算是学习记录

注解(Annotation)

内置注解

1
2
3
4
@Override :可以确保 重写的方法  的确存在于父类/接口中,可以有效的避免 单词拼错等情况。
@Deprecated:给用于提示,该方法由于安全、性能问题等 已经不推荐使用了。此外,在版本升级时,如果要计划删除一些方法,也通常会在前一个版本中 将该方法加上@Deprecated,然后再在后续版本中删除。

@SuppressWarnings(value="unchecked")//压制警告 (虽然可以使用SuppressWarnings压制警告,但不建议使用。)//忽略对泛型等的检查操作。value值:unchecked ,deprecation(忽略一些过期的API) ,unused (是否未被使用) ,fallthrough(swtich 是否一致往下执行,而没有break);path(忽略 对类路径不存在的检查) ,serialVersionUID(忽略 一个类可以序列化、但却没有序列化的 警告),all

自定义注解

1
2
public @interface MyAnnotation {
}

元注解

元数据:修饰数据的数据

元注解:修饰注解的注解, @Target@Retention@Document@Inherited

@Target:限制注解 可以使用的位置

限制注解 能够使用哪些元素上(属性、方法、类);如果一个注解没有@Target描述,则该注解 可以修饰任何类型的元素; 如果有@Target修饰,该注解就只能用于 被@Target修饰的地方

哪些位置? ElementType.枚举

自定义一个注解

1
2
3
4
5
6
7
8
9
10
11
//修饰该注解 只能在 属性、方法上使用
@Target(value= {ElementType.FIELD ,ElementType.METHOD} )
public @interface MyAnnotation {
/*
用定义方法的形式,定义一个属性 value
方法的名字,就是属性的名字;方法的返回值,就是属性的类型
*/
String value() default "张三";//String value = "张三" ;
int age() default 22 ;
}

使用

1
2
3
4
5
6
7
public class TestMyAnnotation {

@MyAnnotation(value="李四",age=33)
public void test(){

}
}

@Retention:限制注解的生命周期

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
public enum RetentionPolicy {
/**
* Annotations are to be discarded by the compiler.
jvm直接将该注解丢弃
*/
SOURCE,

/**
* Annotations are to be recorded in the class file by the compiler
* but need not be retained by the VM at run time. This is the default
* behavior.
.java -> .class
程序在编译时 会使用注解,在运行时不会使用
*/
CLASS,

/**
* Annotations are to be recorded in the class file by the compiler and
* retained by the VM at run time, so they may be read reflectively.
*
* @see java.lang.reflect.AnnotatedElement
程序在编译以及运行时,都会使用注解
*/
RUNTIME
}

自定义注解如何使用? 结合反射使用。

注解+反射 什么时候会真正使用? 开发框架

使用注解案例

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
package annotaion;

import java.lang.annotation.Annotation;

public class TestMyAnnotation {


@MyAnnotation(value="李四",age=33)
@Deprecated
public static void test() throws Exception{

Annotation[] annotations = Class.forName("annotaion.TestMyAnnotation").getMethod("test").getAnnotations();
for(Annotation a :annotations){
if(a instanceof MyAnnotation ){//@MyAnnotation
System.out.println( ((MyAnnotation)a) .value() );
System.out.println( ((MyAnnotation)a) .age() );
}else{//@Deprecated
System.out.println( "@Deprecated" );
}
}
}

@SuppressWarnings("all")
public static void main(String[] args) throws Exception {
test() ;
}
}

运行结果

1
2
3
李四
33
@Deprecated

@Document

​ javadoc:java帮助文档。 ABC.java -> 帮助文档

​ 默认情况下,javadoc不包含 注解的解释;如果现在javadoc文档中 也包含对注解的说明,则需要使用 @Document标注

例如,一下MyAnnotation注解,会在生成javadoc时,被显示在文档中

1
2
3
4
@Documented
public @interface MyAnnotation {

}

@Inherited:继承

1
2
3
4
5
6
7
8
9
@Inherited
public @interface MyAnnotation {
}

@MyAnnotation
public class A{}

public class B extends A{}//默认情况下,B不会继承A中的注解;如果要想继承,则需要加@Inherited

更多

反射(Reflection)

反射获得对象

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
30
31
32
33
34
35
36
37
38
39
40
41
42
public class Test1 {
public static void main(String[] args) throws ClassNotFoundException {
Person person=new Student();
System.out.println("这个人是:"+person.name);

//方式一:对象获得
Class c1=person.getClass();
System.out.println(c1.hashCode());

//方式二:forname获得
Class c2=Class.forName("com.refection.Student");
System.out.println(c2.hashCode());

//方式三:通过类名.class获得
Class c3=Student.class;
System.out.println(c3.hashCode());

//获得父类
Class c5=c1.getSuperclass();
System.out.println(c5);
}
}
class Person{
public String name;

public Person() {
}

public Person(String name) {
this.name = name;
}
}
class Student extends Person{
public Student(){
this.name="学生";
}
}
class Teacher extends Person{
public Teacher(){
this.name="老师";
}
}

所有类型的Class对象

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
public class Test3 {
public static void main(String[] args) {
Class c1=Object.class;//类
Class c2=Comparable.class;//接口
Class c3=String[].class;//一维数组
Class c4=int[][].class;//二维数组
Class c5=Override.class;//注解
Class c6= ElementType.class;//枚举
Class c7=Integer.class;//基本数据类型
Class c8=void.class;//void
Class c9=Class.class;//Class

System.out.println(c1);
System.out.println(c2);
System.out.println(c3);
System.out.println(c4);
System.out.println(c5);
System.out.println(c6);
System.out.println(c7);
System.out.println(c8);
System.out.println(c9);

int[] a=new int[10];
int[] b=new int[100];

System.out.println(a.getClass().hashCode());
System.out.println(b.getClass().hashCode());
}
}

取得类的信息

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
30
31
32
33
34
35
36
public class Test4 {
public static void main(String[] args) throws ClassNotFoundException {
Class c1=Class.forName("com.refection.User");

System.out.println(c1.getName());
System.out.println(c1.getSimpleName());

System.out.println("==========");
//获得属性
Field[] fields=c1.getFields();//只能找到public属性
fields=c1.getDeclaredFields();

for (Field field : fields) {
System.out.println(field);
}
//获得指定属性

System.out.println("==========");
//获得方法
Method[] methods =c1.getMethods();//本类和及父类public方法
methods=c1.getDeclaredMethods();//本类所有方法
for (Method method : methods) {
System.out.println(method);
}
//获得指定方法

System.out.println("==========");
//获得构造器
Constructor[] constructors=c1.getConstructors();
constructors=c1.getDeclaredConstructors();
for (Constructor constructor : constructors) {
System.out.println(constructor);
}
//获得指定构造器
}
}

创建对象

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
30
31
public class Test5 {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
//获得Class对象
Class c1=Class.forName("com.refection.User");
//构造一个对象
User user= (User) c1.newInstance();//本质调用无参构造器
System.out.println(user);

//通过构造器创建对象
Constructor constructor=c1.getConstructor(int.class,String.class,int.class);
User user1= (User) constructor.newInstance(1,"wnhyang",18);
System.out.println(user1);

//通过反射调用方法
User user2= (User) c1.newInstance();
//反射获取方法
Method method=c1.getDeclaredMethod("setName", String.class);
//invoke调用
method.invoke(user2,"wnhyang");
System.out.println(user2.getName());

//通过反射操作属性
User user3= (User) c1.newInstance();
//通过反射获得属性
Field field=c1.getDeclaredField("name");
//不能直接操作私有属性,需要关闭安全检测,及下面的setAccessible(true);
field.setAccessible(true);
field.set(user3,"wnhyang");
System.out.println(user3.getName());
}
}

参考

https://www.bilibili.com/video/BV1p4411P7V3

总结

在学Spring框架时,都会了解到Spring最重要的IOCAOP,就会听到注解与反射,直到去真正了解这些知识,才会发现其中的联系,不过现在我的理解还不到位,说不了太多东西,相信随着学习的深入,慢慢就会发现其中的奥秘。