Java:关于注解和反射

注解的定义

Annotation JDK 1.5 开始引入的新技术,对 package,class,method,field 做出一些注释,并且,可以被程序或者 IDE 读取写入。

内置注解

@Override (重写)
@Deprecated (废弃) => 被标注则意味着废弃的注解现在被废弃了 (啊哈哈哈哈)
@SafeVarargs (忽略任何使用参数为泛型变量的方法或构造函数调用产生的警告)
@FunctionallInterface (函数式接口) | 编程格式检查
@Repeatable (标识某注解可以在同一个声明上使用多次)
@SuppressWarnings (抑制编译时的警告信息) => 变灰暗的类啥的标识这个注解后会不提示警告

元注解

@Target - 标记这个注解应该是哪种 Java 成员
package java.lang.annotation;
public enum ElementType {
   TYPE,               /* 类、接口(包括注释类型)或枚举声明*/
   FIELD,              /* 字段声明(包括枚举常量)*/
   METHOD,             /* 方法声明*/
   PARAMETER,          /* 参数声明*/
   CONSTRUCTOR,        /* 构造方法声明*/
   LOCAL_VARIABLE,     /* 局部变量声明*/
   ANNOTATION_TYPE,    /* 注释类型声明*/
   PACKAGE             /* 包声明*/
}

@Retention - 标识这个注解怎么保存,是只在代码中,还是编入class文件中,或者是在运行时可以通过反射访问
package java.lang.annotation;
public enum RetentionPolicy {      
/* Annotation信息仅存在于编译器处理期间,编译器处理完之后就没有该Annotation信息了*/
   SOURCE,
/* 编译器将Annotation存储于类对应的.class文件中。默认行为*/    
   CLASS,
/* 编译器将Annotation存储于class文件中,并且可由JVM读入*/
   RUNTIME
}

@Documented - 标记这些注解是否包含在用户文档 javadoc中
@Inherited - 标记这个注解是自动继承的

自定义注解实例

自定义注解一般都会配合反射使用,利用反射获取到标注的方法,变量或者是类,然后对其进行处理

@Documented //可以写在文档里
@Target(ElementType.TYPE) //这个注解在类上描述
@Retention(RetentionPolicy.RUNTIME) //作用域策略, 存储于class中, JVM读入
@Inherited //允许继承
public @interface MyAnnotation {
   String annotationTest() default “Test”;
}

@MyAnnotation("new Test")
public class AnnotationTest {
    public static void main() {
        // ....
    }
}

java的内存模型

程序运行---》类加载器 ----》将数据加载进入方法区,并在堆上生成对应的.class文件 ----》执行栈上的 mian 方法----》初始化变量信息

注:对象的实例化是在堆上进行的,静态变量与常量均是存于方法区中。
image.png

反射

反射是一种通过对象,或者类路径获取到 class的一种技术,它很重要 !!! 反射的效率相对来说,是比较耗时的,在使用的反射的时候,可以通过下面的方法,提高效率:

setAccessible(boolean flag)

如果flag为true 则表示忽略访问权限检查 !(可以访问任何权限的方法)

1.获取class的几种方式

com.java.demo.Book.class 或 Book.class
Class book.getClass();
Class.forName("com.java.demo.Book");
注:前两种方式需要Book类存在,第三种方式是动态编程的方式进行加载, 不需要先建立类

2.获取Constructor

通过指定的参数类型, 获取指定的单个构造方法
getConstructor(参数类型的class对象数组)

例如:
构造方法如下: Person(String name,int age)
得到这个构造方法的代码如下:
Constructor c = p.getClass().getConstructor(String.class,int.class);

获取构造方法数组
getConstructors();

获取所有权限的单个构造方法
getDeclaredConstructor(参数类型的class对象数组)

获取所有权限的构造方法数组
getDeclaredConstructors();

3. 获取Method

getMethod(String methodName , class… clss)
根据参数列表的类型和方法名, 得到一个方法(public修饰的)

getMethods();
得到一个类的所有方法 (public修饰的)

getDeclaredMethod(String methodName , class… clss)
根据参数列表的类型和方法名, 得到一个方法(除继承以外所有的:包含私有, 共有, 保护, 默认)

getDeclaredMethods();
得到一个类的所有方法 (除继承以外所有的:包含私有, 共有, 保护, 默认)

4. 执行对应的方法

//加载类
Class c1 = Class.forName(包名+类名);
//获取构造方法
Constructor c = c1.getConstructor();
//创建对象
Object o = c.newInstance();
//获取类中的指定参数的方法
Method setName = c1.getMethod("setName", String.class);
//忽略权限的获取类中的方法
Method setAge = c1.getDeclaredMethod("setAge", int.class);
setAge.setAccessible(true);
//调用setName()方法
setName.invoke(o, "参数")

5. 获取Field

//加载类
Class clazz= Class.forName(包名+类名);

clazz.getDeclaredField(String filedName)
根据属性的名称, 获取一个属性对象 (所有属性)

clazz.getDeclaredFields()
获取所有属性

clazz.getField(String filedName)
根据属性的名称, 获取一个属性对象 (public属性)

clazz.getFields()
获取所有属性 (public)

实例:
//加载类
Class c = Class.forName(包名+类名);
//获取构造器
Constructor ct = c.getConstrutor();
//创建对象
Object o = ct.newInstance();

//获取属性值
Field name = c.getField("name");
name.set(o, "阿乐");
//忽略权限的获取属性值
Filed age = c.getDeclaredField("age");
name.setAccessible(true);
name.set(o, 21);

6.反射获取注解信息!!!

直接上代码

@Documented
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface MyTestAnnotation {
    String name() default "mao";
    int age() default 18;
}

@MyTestAnnotation(name = "father",age = 50)
public class Father {
}
 /**是否存在对应 Annotation 对象*/
  public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) {
        return GenericDeclaration.super.isAnnotationPresent(annotationClass);
    }

 /**获取 Annotation 对象*/
    public <A extends Annotation> A getAnnotation(Class<A> annotationClass) {
        Objects.requireNonNull(annotationClass);

        return (A) annotationData().annotations.get(annotationClass);
    }
 /**获取所有 Annotation 对象数组*/   
 public Annotation[] getAnnotations() {
        return AnnotationParser.toArray(annotationData().annotations);
    }    

public class test {
   public static void main(String[] args) throws NoSuchMethodException {

        /**
         * 获取类注解属性
         */
        Class<Father> fatherClass = Father.class;
        boolean annotationPresent = fatherClass.isAnnotationPresent(MyTestAnnotation.class);
        if(annotationPresent){
            MyTestAnnotation annotation = fatherClass.getAnnotation(MyTestAnnotation.class);
            System.out.println(annotation.name());
            System.out.println(annotation.age());
        }

        /**
         * 获取方法注解属性
         */
        try {
            Field age = fatherClass.getDeclaredField("age");
            boolean annotationPresent1 = age.isAnnotationPresent(Age.class);
            if(annotationPresent1){
                Age annotation = age.getAnnotation(Age.class);
                System.out.println(annotation.value());
            }

            Method play = PlayGame.class.getDeclaredMethod("play");
            if (play!=null){
                People annotation2 = play.getAnnotation(People.class);
                Game[] value = annotation2.value();
                for (Game game : value) {
                    System.out.println(game.value());
                }
            }
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
    }
}

image.png
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容