Java 注解(Annotation)又称 Java 标注,是 JDK5.0 引入的一种注释机制
Java 语言中的类、方法、变量、参数和包等都可以被标注。Java 标注可以通过反射获取标注内容。在编译器生成类文件时,标注可以被嵌入到字节码中。Java 虚拟机可以保留标注内容,在运行时可以获取到标注内容 。 当然它也支持自定义 Java 标
可简单理解为标签
元注解顾名思义我们可以理解为注解的注解
@Retention(RetentionPolicy.SOURCE),注解仅存在于源码中,在class字节码文件中不包含
@Retention(RetentionPolicy.CLASS), 默认的保留策略,注解会在class字节码文件中存在,但运行时无法获得
@Retention(RetentionPolicy.RUNTIME), 注解会在class字节码文件中存在,在运行时可以通过反射获取到
@Retention(RetentionPolicy.RUNTIME) public @interface MyAnnotation { }
@Target(ElementType.TYPE) public @interface MyAnnotation { }
@Documented public @interface MyAnnotation { }
@Retention(RetentionPolicy.RUNTIME) @Documented @Target(ElementType.TYPE) @Inherited public @interface MyAnnotation { }
@MyAnnotation public class Test { } class Test1 extends Test{ }
注解 MyAnnotation被 @Inherited 修饰,之后类 Test 被 MyAnnotation 注解,类 Test1 继承 Test,那么类 Test1 也拥有 MyAnnotation 这个注解。
//相当于一堆注解 @Retention(RetentionPolicy.RUNTIME) public @interface Values { Value[] value(); }
@Retention(RetentionPolicy.RUNTIME) @Repeatable(Values.class) public @interface Value { String id() default "value"; }
public class Test { @Value("hello") @Value("world") public static void test(String var1, String var2) { System.out.println(var1 + " " + var2); } public static void main(String[] args) { Method[] methods = Test.class.getMethods(); for (Method method : methods){ if (method.getName().equals("test")) { Annotation[] annotations = method.getDeclaredAnnotations(); System.out.println(annotations.length); System.out.println(method.getName() + " = " + Arrays.toString(annotations)); } } } }
在注解中定义属性时它的类型必须是 8 种基本数据类型外加 类、接口、注解及它们的数组
注解中属性可以有默认值,默认值需要用 default 关键值指定
如果一个注解内仅仅只有一个名字为 value 的属性时,应用这个注解时可以直接接属性值填写到括号内
这里我们暂时先使用以下反射,稍后详细讲述反射
@Retention(RetentionPolicy.RUNTIME) public @interface Values { Value[] value(); }
@Retention(RetentionPolicy.RUNTIME) @Repeatable(Values.class) public @interface Value { String id() default "id"; String name() default "name"; }
@Value(id = "1",name = "zhangsan") @Value(id = "2",name = "lisi") public class Test { public static void main(String[] args) { if (Test.class.isAnnotationPresent(Values.class)){ Values annotation = Test.class.getAnnotation(Values.class); Value[] values = annotation.value(); for (Value value : values) { System.out.println("id="+value.id()); System.out.println("name="+value.name()); } } } }
id=1 name=zhangsan id=2 name=lisi
属性、方法上的注解照样是可以的,同样还是要假手于反射
@Retention(RetentionPolicy.RUNTIME) public @interface Values { Value[] value(); }
@Retention(RetentionPolicy.RUNTIME) @Repeatable(Values.class) public @interface Value { String id() default "id"; String name() default "name"; }
import java.lang.reflect.Field; import java.lang.reflect.Method; @Value(id = "-1",name = "yoya") @Value(id = "0",name = "ruoye") public class Test { @Value(id = "1",name = "zhangsan") public int a; @Value(id = "2",name = "lisi") public void todo(){ } public static void main(String[] args) { boolean hasAnnotation = Test.class.isAnnotationPresent(Values.class); if ( hasAnnotation ) { Values values = Test.class.getAnnotation(Values.class); //获取类的注解 System.out.println("类注解======================"); System.out.println(values); } try { Field a = Test.class.getDeclaredField("a"); a.setAccessible(true); //获取一个成员变量上的注解 Value value = a.getAnnotation(Value.class); if ( value != null ) { System.out.println("属性注解======================"); System.out.println(value.id()); System.out.println(value.name()); } Method testMethod = Test.class.getDeclaredMethod("todo"); if (testMethod!=null) { // 获取方法中的注解 System.out.println("方法注解======================"); Value declaredAnnotation = testMethod.getDeclaredAnnotation(Value.class); if ( value != null ){ System.out.println(declaredAnnotation.id()); System.out.println(declaredAnnotation.name()); } } } catch (Exception e) { System.out.println(e.getMessage()); } } }
将类的各个组成部分封装为其他对象,这就是反射机制
可以在程序运行过程中,操作这些对象
可以解耦,提高程序的可扩展性
过多的反射会影响性能
同一个字节码文件(*.class)在一次程序运行过程中,只会被加载一次,不论通过哪一种方式获取的Class对象都是同一个
一般不使用这种方式
public class Student { }
public class Test { public static void main(String[] args) { Student student = new Student(); System.out.println(student.getClass()); System.out.println(student.getClass().getName()); } }
class com.ruoye.Student com.ruoye.Student
需要导包
public class Student { }
public class Test { public static void main(String[] args) { System.out.println(Student.class); } }
class com.ruoye.Student
public class Student { }
public class Test { public static void main(String[] args) throws ClassNotFoundException { Class<Student> studentClass = (Class<Student>) Class.forName("com.ruoye.Student"); System.out.println(studentClass.getName()); } }
com.ruoye.Student
public class Student { private int num; private String name; public Student() { } private Student(int num) { this.num = num; } public Student(String name) { this.name = name; } private Student(int num, String name) { this.num = num; this.name = name; } }
public class Test { public static void main(String[] args) throws NoSuchMethodException { Class<Student> studentClass = Student.class; System.out.println("所有构造函数================"); Constructor<?>[] declaredConstructors = studentClass.getDeclaredConstructors(); for (Constructor<?> declaredConstructor : declaredConstructors) { System.out.println(declaredConstructor); } System.out.println("公有构造函数================="); Constructor<?>[] constructors = studentClass.getConstructors(); for (Constructor<?> constructor : constructors) { System.out.println(constructor); } System.out.println("指定参数的所有构造器=============="); Constructor<Student> constructor = studentClass.getDeclaredConstructor(int.class); System.out.println(constructor); System.out.println("指定参数的公开构造器=============="); Constructor<Student> constructor1 = studentClass.getConstructor(String.class); System.out.println(constructor1); } }
所有构造函数================ private com.ruoye.Student(int,java.lang.String) public com.ruoye.Student(java.lang.String) private com.ruoye.Student(int) public com.ruoye.Student() 公有构造函数================= public com.ruoye.Student(java.lang.String) public com.ruoye.Student() 指定参数的所有构造器============== private com.ruoye.Student(int) 指定参数的公开构造器============== public com.ruoye.Student(java.lang.String)
public class Student { private int num; private String name; public Student() { } private Student(int num) { this.num = num; } public Student(String name) { this.name = name; } private Student(int num, String name) { this.num = num; this.name = name; } @Override public String toString() { return "Student{" + "num=" + num + ", name='" + name + '\'' + '}'; } }
public class Test { public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException { Class<Student> studentClass = Student.class; Constructor<Student> declaredConstructor = studentClass.getDeclaredConstructor(int.class, String.class); //暴力反射 declaredConstructor.setAccessible(true); Student zhangsan = declaredConstructor.newInstance(1, "zhangsan"); System.out.println(zhangsan); } }
public class Student { public boolean flag; private int num; private String name; public Student() { } private Student(int num) { this.num = num; } public Student(String name) { this.name = name; } private Student(int num, String name) { this.num = num; this.name = name; } public boolean isFlag() { return flag; } public void setFlag(boolean flag) { this.flag = flag; } public int getNum() { return num; } public void setNum(int num) { this.num = num; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "Student{" + "num=" + num + ", name='" + name + '\'' + '}'; } }
public class Test { public static void main(String[] args) throws NoSuchFieldException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException { Class<Student> studentClass = Student.class; System.out.println("获取所有字段=============="); Field[] fields = studentClass.getDeclaredFields(); for (Field field : fields) { System.out.println(field.getName()); } System.out.println("获取公有字段=============="); Field[] fields1 = studentClass.getFields(); for (Field field : fields1) { System.out.println(field.getName()); } System.out.println("获取特定字段==========="); Field num = studentClass.getDeclaredField("num"); System.out.println(num.getName()); System.out.println("为字段设置值============"); Student student = studentClass.getDeclaredConstructor(null).newInstance(); student.setName("ruoye"); System.out.println(student.toString()); } }
public class Student { private void sleep(int a){ System.out.println("sleep"); } public void study(String name){ System.out.println("study"); } }
public class Test { public static void main(String[] args) throws NoSuchFieldException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException { Class<Student> studentClass = Student.class; System.out.println("获取所有方法================"); Method[] declaredMethods = studentClass.getDeclaredMethods(); for (Method declaredMethod : declaredMethods) { System.out.println(declaredMethod); } System.out.println("获取公有方法(包含父类的方法)================"); Method[] declaredMethods1 = studentClass.getMethods(); for (Method declaredMethod : declaredMethods1) { System.out.println(declaredMethod); } System.out.println("获取指定公共方法================"); Method study = studentClass.getMethod("study", String.class); System.out.println(study); System.out.println("获取指定方法================"); Method sleep = studentClass.getDeclaredMethod("sleep", int.class); Student student = studentClass.getDeclaredConstructor(null).newInstance(); sleep.setAccessible(true); System.out.println(sleep); //唤醒方法 sleep.invoke(student,1); } }
public class Student { private void sleep(int a){ System.out.println("sleep:"+a); } public void study(String name){ System.out.println(name+":study"); } public static void run(String name){ System.out.println(name+":run"); } }
public class Test { public static void main(String[] args) throws NoSuchFieldException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException { Class<Student> studentClass = Student.class; Method sleep = studentClass.getDeclaredMethod("sleep", int.class); Student student = studentClass.getDeclaredConstructor(null).newInstance(); sleep.setAccessible(true); System.out.println(sleep); sleep.invoke(student,1); Method run = studentClass.getDeclaredMethod("run", String.class); System.out.println(run); //方法是静态的,那么可以忽略指定的 obj 参数。该参数可以为 null //方法所需的形参数为 0,则所提供的 args 数组长度可以为 0 或 null //方法是静态的,并且尚未初始化声明此方法的类,则会将其初始化 run.invoke(null,"zhangsan"); } }