注解 Annotation
-
本质是一个接口,继承
java.lang.annotation.Annotation接口;- 注解的属性就是接口中的抽象方法;
- 可以使用
default给属性赋默认值;
// @Override 注解 @Target(ElementType.METHOD) @Retention(RetentionPolicy.SOURCE) public @interface Override { } // @SuppressWarnings 注解 @Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE}) @Retention(RetentionPolicy.SOURCE) public @interface SuppressWarnings { String[] value(); } // 自定义注解 元注解 public @interface 注解名称{ 属性列表 default "xxx"; } -
元注解: 描述注解的注解:
- @Target 声明注解的位置,属性 ElementType
- TYPE:类与接口上;
- FIELD:成员变量上;
- METHOD:方法体上;
- PARAMETER:方法参数上;
- ……
- @Retention 声明注解将被保留的阶段,属性 RetentionPolicy
- SOURCE:只保留在源文件,编译成 class 文件时就不再存在;
- 检查性作用,@Override、@SuppressWarning
- CLASS(默认):保留到 class 文件,加载 class 时遗弃;
- 编译期生成辅助性代码,@Lombok
- RUNTIME:保存到 class 文件中,随 class 文件一起被加载进 JVM;
- 运行时获取(通过反射)
- SOURCE:只保留在源文件,编译成 class 文件时就不再存在;
- @Inherited 声明注解是否被子类继承;
- @Target 声明注解的位置,属性 ElementType
-
反射获取运行时注解:
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @interface ClassInfo { String value(); } @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) @interface FieldInfo { int value() default 666; } @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @interface MethodInfo { String name(); } @ClassInfo("MyAnnotationTest") class MyAnnotation { @FieldInfo int anno; @FieldInfo(888) int tation; @MethodInfo(name = "myPrint") public void print() { } public static void main(String[] args) throws NoSuchMethodException { Class<?> clazz = MyAnnotation.class; ClassInfo classInfo = clazz.getAnnotation(ClassInfo.class); System.out.println(classInfo.value()); Field[] fields = clazz.getDeclaredFields(); FieldInfo fieldInfo = null; for (Field field : fields) { fieldInfo = field.getAnnotation(FieldInfo.class); System.out.println(fieldInfo.value()); } Method method = clazz.getMethod("print"); MethodInfo methodInfo = method.getAnnotation(MethodInfo.class); System.out.println(methodInfo.name()); } }
反射 Reflection
-
Java 是静态语言,但具有一定的动态性。反射就是一个体现,它可以让我们在运行时分析一个类。JVM 加载一个类后会为该类生成一个 Class<T>类的对象,这个 Class 对象就封装了类的各个部分信息,我们可以通过 Class 对象来在运行时对类进行分析,执行其相应方法。
-
获取 Class 对象的三种方式:
对象名.getClass(),一般不用;类名.class必须导包,依赖太强,不用;- 不会初始化 Class 对象;
Class.forName(全类名)最常用;- 会初始化 Class 对象;
-
使用反射
- 先定义一个类
public class MyReflection { public int publicField; private String privateField; public MyReflection() { System.out.println("公有无参构造函数执行了"); } private MyReflection(int publicField, String privateField) { this.publicField = publicField; this.privateField = privateField; System.out.println("私有带参构造函数执行了"); } // get、set方法...省略 public void showPublic(){ System.out.println("public方法被调用了"); } private void showPrivate(){ System.out.println("private方法被调用了"); } public static void showStatic(s){ System.out.println(s); } }- 获取并执行构造方法:
public static void testConstructor() throws Exception { // 获取 Class对象 Class clazz = Class.forName("com.reflection.MyReflection"); // 获取所有公有构造方法 Constructor[] constructors = clazz.getConstructors(); for (Constructor c : constructors) { System.out.println(c); } System.out.println(); // 获取所有构造方法,包括私有等 constructors = clazz.getDeclaredConstructors(); for (Constructor c : constructors) { System.out.println(c); } System.out.println(c); // 获取指定构造方法,参数为要获取的构造方法的参数的class对象; Constructor constructor = clazz.getDeclaredConstructor(int.class,String.class); // 暴力反射,忽略访问修饰符 constructor.setAccessible(true); // 执行构造方法 MyReflection o = (MyReflection) constructor.newInstance(1, "1"); // 打印验证 System.out.println(o.getPrivateField() + o.getPublicField()); } // ----------执行结果-------- public com.reflection.MyReflection() public com.reflection.MyReflection() private com.reflection.MyReflection(int,java.lang.String) 私有带参构造函数执行了 11- 获取成员变量:
public static void testField() throws Exception { Class clazz = Class.forName("com.reflection.MyReflection"); System.out.println("-----获取所有公有属性-----"); Field[] fields = clazz.getFields(); for (Field field : fields) { System.out.println(field); } System.out.println("-----获取所有属性-----"); fields = clazz.getDeclaredFields(); for (Field field : fields) { System.out.println(field); } System.out.println("-----获取指定属性,并调用-----"); Field privateField = clazz.getDeclaredField("privateField"); privateField.setAccessible(true); MyReflection o = (MyReflection) clazz.getConstructor(null).newInstance(); privateField.set(o,"反射修改了私有属性"); System.out.println(o.getPrivateField()); } // ---------结果------------ -----获取所有公有属性----- public int com.reflection.MyReflection.publicField -----获取所有属性----- public int com.reflection.MyReflection.publicField private java.lang.String com.reflection.MyReflection.privateField -----获取指定属性,并调用----- 公有无参构造函数执行了 反射修改了私有属性- 获取方法并调用:
public static void testMethod() throws Exception { Class clazz = Class.forName("com.reflection.MyReflection"); System.out.println("-----获取所有公有方法-----"); Method[] methods = clazz.getMethods(); for (Method m : methods) { System.out.println(m); } System.out.println("-----获取所有方法-----"); methods = clazz.getDeclaredMethods(); for (Method m : methods) { System.out.println(m); } System.out.println("-----获取指定方法,并调用-----"); Method method = clazz.getMethod("showStatic",String.class); // 参数:执行对象 与 传参 // 因为是静态方法,所以传递 null method.invoke(null, "静态方法执行了"); method = clazz.getDeclaredMethod("showPrivate"); MyReflection o = (MyReflection) clazz.getConstructor(null).newInstance(); method.invoke(o); } //-----结果----- -----获取所有公有方法----- 略 -----获取所有方法----- 略 -----获取指定方法,并调用----- 静态方法执行了 公有无参构造函数执行了 private方法被调用了