注解与注释其实非常的相似,只不过注释是用来让开发人员知道某段代码的作用是什么都有哪些参数等,而注解则是写给程序看的一个“注释”,注解中主要包含了它本身的名称,以及它的参数,单纯地看一个注解其实与注释没啥区别。但注解往往会与反射组合使用,反射可以让我们在程序运行时观察并操作某个类中的信息,当然包括注解,这在实现一些框架的过程中有很大作用(比如实现实体类到数据库表的自动映射)。
注解(Annotation) 元注解
元注解的作用是注解其他的注解,Java定义了4个标准的meta-annotation类型,他们被用来提供对其他annotation类型的说明。
存在包java.lang.annotation中
四个标准元注解:
注解注解的注解,也就是注解的注解,只能用在注解上。
@Target 用于描述注解的使用范围(如方法、类、字段上等)
@Retention 表示在什么级别保存该注释信息,用于描述注解的生命周期
@Document 说明该注解将被包含在javadoc中
@Inherited 说明子类可以继承父类中的该注解
@Target 示例:
1 2 3 @Target(ElementType.METHOD) public @interface myAnnotation {}
其中参数ElementType的可选值有:
TYPE
FIELD
METHOD
PARAMETER
CONSTRUCTOR
LOCAL_VARIABLE
ANNOTATION_TYPE
PACKAGE
TYPE_PARAMETER
TYPE_USE
@Retention
表示注解在什么范围有效,如源码级别、编译后的class级别、运行时级别
示例:
1 2 3 4 @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface MyAnnotation {}
其中参数的可选值有:
SOURCE
CLASS
RUNTIME
参数的关系为包含 关系,RUNTIME > CLASS > SOURCE
自定义注解 自定义多参数的注解示例:
1 2 3 4 5 6 7 8 @Target({ElementType.METHOD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) public @interface MyAnnotation { String name () default "defaultName" ; String school () ; }
自定义只带一个参数的注解示例:
如果之定义一个参数最好将参数命名为value()
,因为命名为value在使用注解时可以省略value =
1 2 3 4 5 6 7 @Target({ElementType.METHOD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) public @interface MyAnnotation { String[] value(); }
反射(Reflection)
反射式编程 (英语:reflective programming)或反射 (英语:reflection),是指计算机程序在运行时(runtime)可以访问、检测和修改它本身状态或行为的一种能力。用比喻来说,反射就是程序在运行的时候能够“观察”并且修改自己的行为。——维基百科
理解反射 我对反射的一个比较形象的理解是,java中的反射与物理中光的反射也有一些相似的地方。在现实生活中,我们能够通过镜子看到某个物体反射后的像,而java中的反射就是以类加载过程中会生成的Class对象 作为“镜子”,通过这面镜子,我们能在程序运行时观察并操作某个类的内部结构。因此学习反射绕不开对Class类的学习。(个人的理解,可能表达并不准确)
反射机制提供的功能
在运行时判断任意一个对象所属的类型
在运行时构造任意一个类的对象
在运行时判断任意一个类所具有的成员变量和方法
在运行时获取泛型信息
在运行时调用任意一个对象的成员变量和方法
在运行时处理注解
生成动态代理
……
理解java中的Class类 Class类
Class本身也是一个类
Class类只能由系统创建 对象
一个加载的类在JVM中有且仅有一个Class实例
一个Class对象对应的是一个加载到JVM中的一个.class文件
每个类的实例都会知道自己是由哪个Class实例所生成
通过Class可以完全地得到一个类中的所有被加载的结构
Class类是Reflection的根源,针对任何你想动态加载、运行的类,唯有先获得相应的Class对象
获取Class对象的几种方式 这里我们写了两个类Person与Student,其中Student继承Person,本文章中所有的Person类与Student类都是以下列出的代码。
Person类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 public class Person { public String name; public Person () { } public String getName () { return name; } public void setName (String name) { this .name = name; } }
Student类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 import com.experiment.annotation.MyAnnotation;import com.experiment.annotation.MyAnnotation02;@MyAnnotation(name = "MakerHu", school = "BJTU") public class Student extends Person { @MyAnnotation02("studentCardId") private String studentId; public Student () { } public Student (String name) { this .setName(name); } public String getStudentId () { return studentId; } public void setStudentId (String studentId) { this .studentId = studentId; } }
通过代码可以更好地理解如何获取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 30 31 32 package com.experiment.reflection.getclass;public class Main { public static void main (String[] args) throws ClassNotFoundException { Person student1 = new Student("学生" ); Person student2 = new Student("学生" ); Class c1_1 = student1.getClass(); Class c1_2 = student2.getClass(); Class c2 = Class.forName("com.experiment.reflection.getclass.Student" ); Class c3 = Student.class; Class c4 = Integer.TYPE; Class c5 = c1_1.getSuperclass(); System.out.println("c1_1: " + c1_1.hashCode()); System.out.println("c1_2: " + c1_2.hashCode()); System.out.println("c2: " + c2.hashCode()); System.out.println("c3: " + c3.hashCode()); System.out.println("c4: " + c4); System.out.println("c5: " + c5); } }
以上代码的输出为:
1 2 3 4 5 6 c1_1: 460141958 c1_2: 460141958 c2: 460141958 c3: 460141958 c4: int c5: class com.experiment.reflection.getclass.Person
从c1到c3的输出我们可以发现,不管Class对象是如何获得的,只要其为某个类的Class对象,其在内存中就只有一个,也就是一个类拥有唯一的一个Class对象 。
通过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 30 31 32 33 34 35 36 37 package com.experiment.reflection.getClassMsg;import java.lang.reflect.Constructor;import java.lang.reflect.Field;import java.lang.reflect.Method;public class GetClassMsg { public static void main (String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException { Class c1 = Class.forName("com.experiment.reflection.getclass.Student" ); System.out.println(c1.getName()); System.out.println(c1.getSimpleName()); Field[] fields = c1.getFields(); fields = c1.getDeclaredFields(); Field name = c1.getField("name" ); Field studentId = c1.getDeclaredField("studentId" ); Method[] methods = c1.getMethods(); methods = c1.getDeclaredMethods(); Method setName = c1.getMethod("setName" ,String.class); Method setStudentId = c1.getDeclaredMethod("setStudentId" ,String.class); Constructor[] constructors = c1.getConstructors(); Constructor[] constructors1 = c1.getDeclaredConstructors(); Constructor constructor = c1.getConstructor(String.class); Constructor constructor1 = c1.getDeclaredConstructor(null ); } }
动态操作对象 同样,看代码。
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 package com.experiment.reflection.operateObject;import com.experiment.reflection.getclass.Student;import java.lang.reflect.Constructor;import java.lang.reflect.Field;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;public class OperateObject { public static void main (String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchMethodException, NoSuchFieldException { Class c1 = Class.forName("com.experiment.reflection.getclass.Student" ); Student student = (Student)c1.newInstance(); Constructor constructor = c1.getDeclaredConstructor(String.class); Student student1 = (Student) constructor.newInstance("Makerhu" ); Method setStudentId = c1.getDeclaredMethod("setStudentId" , String.class); setStudentId.invoke(student1,"123425" ); Field studentId = c1.getDeclaredField("studentId" ); studentId.setAccessible(true ); studentId.set(student1, "9876543" ); } }
获取泛型信息 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 43 44 45 46 47 48 49 50 import com.experiment.reflection.getclass.Student;import java.lang.reflect.Method;import java.lang.reflect.ParameterizedType;import java.lang.reflect.Type;import java.util.List;import java.util.Map;public class OperateGenericType { public void test01 (Map<String, Student> map, List<Student> list, String str) { System.out.println("test01" ); } public Map<String, Student> test02 () { System.out.println("test02" ); return null ; } public static void main (String[] args) throws NoSuchMethodException { Method method = OperateGenericType.class.getMethod("test01" ,Map.class,List.class,String.class); System.out.println("获取参数类型" ); Type[] genericParameterTypes = method.getGenericParameterTypes(); for (Type genericParameterType : genericParameterTypes) { System.out.println("\n# " + genericParameterType); if (genericParameterType instanceof ParameterizedType){ System.out.println("=================" ); Type[] actualTypeArguments = ((ParameterizedType) genericParameterType).getActualTypeArguments(); for (Type actualTypeArgument : actualTypeArguments) { System.out.println(actualTypeArgument); } } } System.out.println("\n获取返回值类型" ); method = OperateGenericType.class.getMethod("test02" ); Type genericReturnType = method.getGenericReturnType(); if (genericReturnType instanceof ParameterizedType){ Type[] actualTypeArguments = ((ParameterizedType) genericReturnType).getActualTypeArguments(); for (Type actualTypeArgument : actualTypeArguments) { System.out.println(actualTypeArgument); } } } }
输出结果为:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 获取参数类型 ================= class java.lang.String class com.experiment.reflection.getclass.Student ================= class com.experiment.reflection.getclass.Student 获取返回值类型 class java.lang.String class com.experiment.reflection.getclass.Student
获取注解信息 先看看自定义的两个注解MyAnnotation与MyAnnotation02,这两个注解在Student类中被使用,具体看前面的Student类的代码。
注解1:MyAnnotation
1 2 3 4 5 6 7 8 9 10 11 import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;@Target({ElementType.METHOD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) public @interface MyAnnotation { String name () default "defaultName" ; String school () ; }
注解2:MyAnnotation02
1 2 3 4 5 6 7 8 9 10 import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;@Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface MyAnnotation02 { String value () ; }
通过反射获取注解信息:
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 import com.experiment.annotation.MyAnnotation;import com.experiment.annotation.MyAnnotation02;import java.lang.annotation.Annotation;import java.lang.reflect.Field;public class OperateAnnotation { public static void main (String[] args) throws ClassNotFoundException, NoSuchFieldException { Class c1 = Class.forName("com.experiment.reflection.getclass.Student" ); Annotation[] annotations = c1.getAnnotations(); MyAnnotation annotation = (MyAnnotation) c1.getAnnotation(MyAnnotation.class); Field field = c1.getDeclaredField("studentId" ); MyAnnotation02 annotation02 = field.getAnnotation(MyAnnotation02.class); System.out.println(annotation.name()); System.out.println(annotation.school()); System.out.println(annotation02.value()); } }
笔记整理于:【狂神说Java】注解和反射_哔哩哔哩_bilibili