java注解与反射的基本使用(这一篇就够了!)

一、注解(Annotation)

1.什么是注解?
我相信您对注释并不陌生。在信息快速发展的时代,各种优秀的框架可能都离不开注释的使用,比如我们在实现一个接口的方法时,就使用了@Overover注释。说白了,批注就是解释程序,和我们对方法、类的评论没什么不同,但批注可以被其他程序读取进行信息处理,否则和批注没有太大区别。[en]I believe you are no stranger to annotations. In the era of rapid development of information, all kinds of excellent frameworks may be inseparable from the use of annotations, such as @ Override annotations when we implement a method of an interface. To put it bluntly, annotations mean to explain the program, which is no different from our comments on methods and classes, but * * annotations can be read by other programs for information processing, otherwise they are not much different from annotations.
2.内置注解**
内置批注是我们的JDK附带的一些批注。三个常用的注释:[en]Built-in annotations are some of the annotations that come with our jdk. Three commonly used comments:

  • @Override
    这对于修辞来说应该并不陌生,这表明您打算重写超类中的方法声明。[en]This should be no stranger to rhetoric, indicating that you intend to rewrite the method declaration in the superclass.
  • @Deprecated
    这条评论我们应该很熟悉,也可能看不到,但在使用一些方法时,我们肯定会有一条水平线。这个注释可以是修辞上的方法、属性、类,表明程序员不被鼓励使用这些元素,通常是因为它们很危险或有更好的选择。[en]This comment should be familiar to us, and we may not see it, but we are sure to have a horizontal line when using some methods. This comment can be rhetorical methods, attributes, classes, indicating that programmers are not encouraged to use such elements, usually because they are dangerous or have a better choice.
    java注解与反射的基本使用(这一篇就够了!)
  • @SuperWarnings
    此注释主要用于隐藏警告消息。当我们写程序时,我们可能会报告很多黄色警告,但它不影响操作,所以我们可以用这个评论来抑制和隐藏它。与前两个注释不同,我们必须给出注释参数才能正确使用它。[en]This comment is mainly used to suppress warning messages. When we write a program, we may report a lot of yellow warnings, but it does not affect the operation, so we can use this comment to suppress and hide it. Unlike the first two comments, we have to give the annotation parameters in order to use it correctly.

参数说明不建议使用来自过时类或方法的警告取消选中时执行未经检查的转换,例如:使用集合时未指定泛型回落使用Switch语句时发生案例遍历警告路径在类路径中不存在,源文件路径警告Serial当缺少序列时VersionUID定义序列化类上的UID定义最终当任何Finally子句无法完成时有关上述所有内容的所有警告[en]Parameter description deprecation uses warnings from outdated classes or methods warnings when unchecked performs unchecked conversions such as: generic fallthrough is not specified when using collections case traversal occurs when switch statements are used warning that path does not exist in the classpath, source file path warning serial when missing serialVersionUID definition on serialized classes warning finally when any finally clause cannot be completed all warnings about all above

上表显示了@SuperWarning注释的一些参数,可以根据需要使用这些参数。[en]The above table shows some of the parameters of the @ SuperWarnings annotation, which can be used as needed.
@SuperWarnings(“finally”)
@SuperWarnings(value={“unchecked”,”path”})

java注解与反射的基本使用(这一篇就够了!)
3.自定义注解

格式:public @interface 注解名 { 定义体 }

  • 使用@接口自定义批注时,会自动继承java.lang.Annotation接口[en]* when using @ interface custom annotations, the java.lang.annotation.Annotation interface is automatically inherited
  • 这些方法中的每一个实际上都声明一个配置参数[en]* each of these methods actually declares a configuration parameter
  • 方法的名称为参数的名称[en]* the name of the method is the name of the parameter
  • 返回值类型为参数类型(仅基本类型、类、字符串、枚举)[en]* return value type is the type of parameter (only basic type, Class, String, enum)
  • 可以通过DEFAULT声明参数的默认值[en]* you can declare the default value of the parameter through default
  • 如果只有一个参数成员,则一般参数名称为Value[en]* if there is only one parameter member, the general parameter name is value
  • 使用注释元素时,我们必须有一个值。我们可以定义缺省值、空字符串、0或-1。[en]* We must have a value when using annotation elements. We can define default values, empty strings, 0 or-1.
public @interface TestAnnotation {

    //参数默认为空
    String value() default "";

}

4.元注解
当我们定制批注时,我们需要使用Java提供的元批注,这是负责批注的其他批注。Java定义了四种标准元注释类型,用于为其他注释类型提供声明。[en]When we customize annotations, we need to use the meta-annotations provided by java, which are the other annotations that are responsible for annotations. Java defines four standard meta-annotation types that are used to provide declarations for other annotation types.

  • @Target
    这个注释的目的主要是描述注释的使用范围,说白了,在哪里可以使用我们自己定义的注释。[en]The purpose of this annotation is mainly to describe the scope of use of annotations, to put it bluntly, where our own defined annotations can be used.

所修饰范围取值ElementTypepackage 包PACKAGE类、接口、枚举、Annotation类型TYPE类型成员(方法,构造方法,成员变量,枚举值)CONSTRUCTOR:用于描述构造器。FIELD:用于描述域。METHOD:用于描述方法方法参数和本地变量LOCAL_VARIABLE:用于描述局部变量。PARAMETER:用于描述参数

java注解与反射的基本使用(这一篇就够了!)
我们定制了一个注释,以便您可以在声明元注释时看到提供给我们的所有常量。让我们以ElementType.METHOD为例。[en]We customize an annotation so that you can see all the constants that provide us when declaring meta-annotations. Let’s take ElementType.METHOD as an example.
@Target(ElementType.METHOD)
public @interface TestAnnotation {

    //参数默认为空
    String value() default "";

}

我们在这里测试这个注释。[en]We’re here to test this annotation.

java注解与反射的基本使用(这一篇就够了!)
因此,很明显,当我们将注释放在变量上时,编译器报告我们一个错误,这意味着这里不允许注释。然后把它放在方法中,你可以悄悄地把它放在那里。[en]As a result, it is obvious that when we put the comment on our variable, the compiler reported us an error, which means that the comment is not allowed here. And put it in the method, you can put it there quietly.
  • @Retention
    这个注释的目的是,我们需要告诉编译器,我们需要在什么级别保存注释信息,以描述注释的生命周期。[en]The purpose of this annotation is that we need to tell the compiler at what level we need to save the annotation information to describe the life cycle of the annotation.

值RetentionPolicy函数源代码在源文件中有效(即源文件保留)类在类文件中有效(即类保留)运行时在运行时有效(即运行时保留)注:运行时可通过反射机制读取[en]Value RetentionPolicy function SOURCE valid in source file (that is, source file retention) CLASS is valid in class file (that is, class retention) RUNTIME is valid at run time (that is, run time retention) Note: it can be read by reflection mechanism when RUNTIME

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface TestAnnotation {

    //参数默认为空
    String value() default "";

}

一般来说,我们可以使用运行时。这样,我们还可以在程序运行时通过反射机制阅读评论。[en]In general, we can use RUNTIME. In this way, we can also read the comment through the reflection mechanism while the program is running.

  • @Document
  • *@Inherited

以上两个注解我们用得不多,大家可以对自己的百度感兴趣,而且文档树似乎是生成的。[en]The above two notes we do not use a lot, you can be interested in their own Baidu, and the generation of document tree seems.
我们可以稍后通过反射机制阅读我们的评论。[en]We can read our comments later through the reflection mechanism.

二、反射(Reflect)

1.什么是反射?
反射意味着我们可以加载、检测和使用在编译时完全未知的类。是一种动态机制,允许我们通过字符串指导程序实例化、操作属性和调用方法。这使得代码更加灵活,但也带来了更多的资源开销。[en]Reflection means that we can load, detect, and use classes that are completely unknown at compile time. Is a dynamic mechanism that allows us to direct program instantiation, manipulate properties, and invoke methods through strings. It makes the code more flexible, but it also brings more resource overhead.
装入类后,堆内存中会生成一个类型为Class的对象(一个类只有一个Class对象),其中包含类的完整结构信息。通过这个对象,我们可以看到类的结构。这个对象就像一面镜子,通过它我们可以看到类的结构,所以我们直观地称之为反射。[en]After the class is loaded, an object of type Class (a class has only one Class object) is generated in heap memory, which contains the complete structural information of the class. We can see the structure of the class through this object. This object is like a mirror, through which we can see the structure of the class, so we visually call it reflection.
2.class类
当我们使用反射时,我们首先需要获取我们需要的类,而java.lang.Class是一个基本的类,它对于在Java中表示类型(类/接口/枚举/注释/原始类型/空)本身是非常特殊的。[en]When we use reflection, we need to get the class we need first, and java.lang.Class is an essential class, which is very special to represent the type (class/interface/enum/annotation/primitive type/void) itself in java.

  • Class类的对象包含了某个被加载类的结构。一个被加载的类对应一个 Class对象。
  • 当加载类时,或者当JVM调用加载器(类加载器)的fineClass()时,JVM会自动生成一个Class对象。[en]* when a class is loaded, or when the defineClass () of the loader (class loader) is called by JVM, JVM automatically generates a Class object.

我们应该如何获取Class类的对象?
让我们首先创建一个普通的实体类。[en]Let’s first create a normal entity class.

package sml.reflect;

public class User {

    //这里name用的是私有类型
    private String name;
    //这里age用的是公有类型
    public int age;

    //无参构造器
    public User(){}

    //有参构造器
    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}
  1. 通过Class.forName()获取( 最常用
public class TestReflect {
    public static void main(String[] args) {
        try {
            //获取User的Class对象,参数为需要获取类对象的全类名
           Class aClass = Class.forName("sml.reflect.User");
        //因为是动态编译,所有我们需要抛出类未找到的异常
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}
  1. 通过getClass()获取
public class TestReflect {
    public static void main(String[] args) {
        //new一个user对象
        User user = new User();
        //通过user对象来获取User类对象
        Class aClass = user.getClass();
    }
}
  1. 通过.class获取
public class TestReflect {
    public static void main(String[] args) {
        //通过导包获取类名点class来获取类对象
        Class aClass = User.class;
    }
}

3.反射的基本操作
在我们获得Class对象之后,我们可以获得有关类的一些信息。下面让我们来看看一些常见的问题。[en]After we get the Class object, we can get some information about the class. Here let’s take a look at some common ones.
1)获取类名

Class aClass = Class.forName("sml.reflect.User");
 //获取全类名
String name = aClass.getName();
 //获取简单的类名
String simpleName = aClass.getSimpleName();

结果:[en]Results:

java注解与反射的基本使用(这一篇就够了!)
2)获取类的字段、某些变量
Class aClass = Class.forName("sml.reflect.User");

//获取该类的所有public字段,包括父类的
Field[] fields = aClass.getFields();
//根据字段名获取该类的public字段
Field field = aClass.getField("age");

//获取该类的所有字段,不包括父类(仅自定义)
Field[] fields1 = aClass.getDeclaredFields();
//根据字段名获取该类的字段
Field field1 = aClass.getDeclaredField("name");

注意:我们仔细看注释,不带Declared的方法职能获取到public字段,且包括父类的,带Declared的方法可以获取到所有的自定义的字段!
测试它:[en]Test it:

java注解与反射的基本使用(这一篇就够了!)
java注解与反射的基本使用(这一篇就够了!)
3)获取类的方法
Class aClass = Class.forName("sml.reflect.User");

//获取该类的所有public方法,包括父类的
Method[] methods = aClass.getMethods();
//根据方法名获取该类的public方法
Method method = aClass.getMethod("getName");
//如果该类为重写方法,可以在第二个参数加上重写方法的参数类型,不写为无参数的方法
Method paramMethod = aClass.getMethod("getName",String.class)

//获取该类的所有方法,不包括父类(仅自定义)
Method[] declaredMethods = aClass.getDeclaredMethods();
//根据方法名获取该类的方法
Method declaredMethod = aClass.getDeclaredMethod("getName");

注:获取方法的方式与获取字段的方法一样,在这里我们需要注意的是重写的方法,一个类中存在俩个或多个方法名是一样的,因此在根据方法名获取方法时,提供第二个参数,为可变参数。参数类型为我们获取方法的参数类型的类,如果不写默认为无参方法。

4)获取类的构造器

 Class aClass = Class.forName("sml.reflect.User");

//获取该类的所有构造器,包括父类
Constructor[] constructors = aClass.getConstructors();
//根据构造器的参数类型来获取指定构造器,不写为无参构造器
Constructor constructor = aClass.getConstructor();
Constructor constructor1 = aClass.getConstructor(String.class,int.class);

//获取该类的所有构造器,不包括父类
Constructor[] declaredConstructors = aClass.getDeclaredConstructors();
//根据构造器的参数类型来获取指定的自定义构造器,不写为无参构造器
Constructor declaredConstructor = aClass.getDeclaredConstructor();
Constructor declaredConstructor1 = aClass.getDeclaredConstructor(String.class, int.class);

注:在我们获取类构造器和类方法时涉及到可变参数的知识,大家可以自行百度一下,或者查阅官方文档,也不难,就是在我们不确定参数有几个时,就可以写成可变参数,我们在使用时可以传多个参数。注意我们写的参数都为 类对象!

我们从构造函数得到的第一个想法应该是实例化对象。[en]The first idea we get from the constructor should be to instantiate the object.

5)类的实例化

Class aClass = Class.forName("sml.reflect.User");

//通过class类直接实例化,使用的是User类的无参构造器
User user = (User) aClass.newInstance();

//获取构造器来进行实例化,这里获取有参构造器
Constructor declaredConstructor = aClass.getDeclaredConstructor(String.class, int.class);
//根据构造器进行实例化
User user1 = (User) declaredConstructor.newInstance("sml",18);

注:我们在使用类对象直接实例化时,一定要确保需实例化的类中存在无参构造器,否则会报错。默认获取的是Object类型,因此最后需要进行下类型转化。
测试:让我们覆盖User类中的toString方法,并查看我们在Print下获得的对象[en]Test: let’s override the toString method in the User class and take a look at the object we got under print

java注解与反射的基本使用(这一篇就够了!)
我们得到对象是否应该通过获取的对象调用该方法,不!我们通过反射调用对象的方法。[en]We get whether the object should call the method through the acquired object, NO! We call the object’s method through reflection.
6)方法的调用
Class aClass = Class.forName("sml.reflect.User");

User user = (User) aClass.newInstance();
//获取setName方法
Method setName = aClass.getDeclaredMethod("setName", String.class);
//通过获取的方法来调用(invoke),invoke方法有俩个参数
//第一个是调用底层方法的对象,也就是通过哪个对象来调用方法
//第二个为可变参数,是用于方法调用的参数
setName.invoke(user,"sml");

测试:让我们打印对象以查看方法是否已执行[en]Test: let’s print the object to see if the method has been executed

java注解与反射的基本使用(这一篇就够了!)
注:如果我们调用的方法为私有方法,虽然编译器通过,在运行时会报错的( java.lang.IllegalAccessException ),这是因为java的安全检查。我们可以使用setAccessible(true)这个方法来跳过安全检查。
Class aClass = Class.forName("sml.reflect.User");

User user = (User) aClass.newInstance();
Method setName = aClass.getDeclaredMethod("setName", String.class);
//若setName为私有方法,跳过安全检查
setName.setAccessible(true);
setName.invoke(user,"sml");

当我们编写程序时,我们通常通过getset方法来操作场,下面我们也通过反射来操作场。[en]When we write the program, we usually manipulate the field through the getset method, and below we also manipulate the field through reflection.
7)字段的操作

Class aClass = Class.forName("sml.reflect.User");

User user = (User) aClass.newInstance();
//获取name字段
Field name = aClass.getDeclaredField("name");
//通过该字段的set方法来改变该字段的值,该字段有俩个参数
//第一个为应该修改其字段的参数
//第二个为被修改字段的新值
name.set(user,"sml");

测试:让我们打印对象并查看名称字段是否已更改[en]Test: let’s print the object and see if the name field has changed

java注解与反射的基本使用(这一篇就够了!)
啊,错误的报告。看看这个错误看起来很熟悉,我们上面说过,这是因为我们的名字段是私有的,我们不能直接操作这个字段,我们需要跳过安全检查,我们添加了name.setAccesable(True);再次运行。[en]Ah, wrong report. Look at this mistake look familiar, we said above, this is because our name field is private, we can not directly manipulate the field, we need to skip the security check, we add name.setAccessible (true); run again.
java注解与反射的基本使用(这一篇就够了!)

这是不够的,反射很强,我们说反射的对象就像一面镜子,我们可以得到我们能看到的一切,让我们读参数泛型,并返回值泛型![en]This is not enough, the reflection is very strong, we said that the reflected object is like a mirror, we can get everything we can see, let’s read the parameter generics and return the value generics!
8)泛型的操作(Generic)

泛型应该是我们所熟悉的。Java使用泛型擦除机制引入泛型。换句话说,Java的泛型只供编译器的javac使用,确保数据的安全,避免转换的麻烦。但是一旦编译完成,与泛型相关的所有数据都会被擦除。[en]Generics should be familiar to us. Java uses * generic erasure mechanism * to introduce generics. In other words, java’s generics are only for the compiler javac to use, * ensure the security of data and avoid the hassle of casting * . But once the compilation is complete, all data related to generics is erased.
为了通过反射来操作这些类型,以满足实际开发的需要,Java增加了参数类型通用阵列类型TypeVariableWildcardType类型,以表示无法规范化到Class类中但与原始类型同名的类型。这四种类型实现了Type接口。[en]In order to operate these types through reflection to meet the needs of actual development, Java has added * ParameterizedType, * GenericArrayType, * * TypeVariable and * WildcardType* types to represent types that cannot be normalized into the Class class but have the same name as the original type. These four types implement the Type interface.

类型含义ParameterizedType参数化类型,带有类型参数的类型,即常说的泛型,如:List《T》TypeVariable类型变量,如参数化类型Map《E,Y》中的Y、K等类型变量,表示泛指任何类GenericArrayType(泛型)数组类型,比如List《T》[],T[]这种。注意,这不是我们说的一般数组,而是表示一种【元素类型是参数化类型或者类型变量的】数组类型WildcardType代表通配符表达式,或泛型表达式,比如【?】【? super T】【? extends T】。虽然WildcardType是Type的一个子接口,但并不是Java类型中的一种

让我们演示一下反射读取参数化为Type类型。[en]Let’s demonstrate the reflection reading ParameterizedType type.

public class TestReflect {

    //测试方法,返回类型与参数都为泛型
    public static Map<string,user> GenericityTest(List<user> list,User user){
        return null;
    }

    public static void main(String[] args) {
        try {
            //&#x5148;&#x83B7;&#x53D6;&#x5230;&#x8BE5;&#x7C7B;
            Class aClass = Class.forName("sml.reflect.TestReflect");
            //&#x83B7;&#x53D6;&#x5230;&#x6D4B;&#x8BD5;&#x65B9;&#x6CD5;
            Method genericityTest = aClass.getDeclaredMethod("GenericityTest", List.class,User.class);
            //&#x83B7;&#x53D6;&#x5230;&#x7C7B;&#x578B;&#x53C2;&#x6570;&#x6570;&#x7EC4;,&#x5C31;&#x662F;&#x83B7;&#x53D6;&#x65B9;&#x6CD5;&#x6240;&#x6709;&#x7684;&#x53C2;&#x6570;&#x7C7B;&#x578B;
            Type[] genericParameterTypes = genericityTest.getGenericParameterTypes();
            for (Type genericParameterType : genericParameterTypes) {
                //&#x8F93;&#x51FA;&#x4E00;&#x4E0B;&#x7C7B;&#x578B;&#x53C2;&#x6570;
                System.out.println(genericParameterType);
                //&#x6211;&#x4EEC;&#x5728;&#x5FAA;&#x73AF;&#x65F6;&#x5224;&#x65AD;&#x8BE5;&#x53C2;&#x6570;&#x7C7B;&#x578B;&#xFF0C;&#x82E5;&#x8BE5;&#x53C2;&#x6570;&#x5C5E;&#x4E8E;&#x53C2;&#x6570;&#x5316;&#x7C7B;&#x578B;
                if(genericParameterType instanceof ParameterizedType){
                    //&#x82E5;&#x5C5E;&#x4E8E;&#x53C2;&#x6570;&#x5316;&#x7C7B;&#x578B;&#xFF0C;&#x5219;&#x83B7;&#x53D6;&#x7C7B;&#x578B;&#x5BF9;&#x8C61;&#x7684;&#x6570;&#x7EC4;&#xFF0C;&#x8868;&#x793A;&#x6B64;&#x7C7B;&#x578B;&#x7684;&#x5B9E;&#x9645;&#x7C7B;&#x578B;&#x53C2;&#x6570;
                    Type[] actualTypeArguments = ((ParameterizedType) genericParameterType).getActualTypeArguments();
                    for (Type actualTypeArgument : actualTypeArguments) {
                        //&#x6253;&#x5370;&#x4E0B;&#x5B9E;&#x9645;&#x7C7B;&#x578B;&#x53C2;&#x6570;
                        System.out.println(actualTypeArgument);
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
</user></string,user>

如果我们看它,它可能会非常复杂。让我们来分析一下。[en]If we look at it, it may be very complicated. Let’s analyze it.
首先,概化测试是我们得到的方法。我们使用概化检验来获得该方法的参数。。这里返回的是Type类型,即所有类型的父接口。让我们打印出来,即返回的List和User,也就是他的两个参数List User和User。[en]First of all, genericityTest is the method we obtained. We use genericityTest to obtain the parameters of the method. * Note * . What is returned here is the Type type, that is, the parent interface of all types. Let’s print it out, that is, the returned List and User, that is, his two parameters * List “User” and User.

java注解与反射的基本使用(这一篇就够了!)
接下来,我们遍历类型参数的数组。我们现在需要的是读取参数化类型。然后对每个类型参数进行判断。如果Type参数属于参数化型别,那么我们得到的是泛型类型的实际类型参数,即UserinList。请注意,只有列表USER属于参数类型,所以您可以看到上表。[en]Next, we iterate through the array of type Type parameters. What we need now is to read the parameterized type. Then we judge each Type parameter. If the Type parameter belongs to the ParameterizedType parameterized type, then we are getting the actual type parameter of the generic type, that is, User, * in * List. Note that only List “User” belongs to the parameterized type, so you can see the above table * .
java注解与反射的基本使用(这一篇就够了!)
注:我们在上面演示的只是获取方法的参数,那么我们如何获取返回值的类型?下面第二个方法
//&#x83B7;&#x53D6;&#x65B9;&#x6CD5;&#x6240;&#x6709;&#x7684;&#x53C2;&#x6570;&#x7C7B;&#x578B;
Type[] genericParameterTypes = genericityTest.getGenericParameterTypes();
//&#x83B7;&#x53D6;&#x8FD4;&#x56DE;&#x503C;&#x7684;&#x53C2;&#x6570;&#x7C7B;&#x578B;&#xFF0C;&#x8FD4;&#x56DE;&#x503C;&#x53EA;&#x6709;&#x4E00;&#x4E2A;&#xFF0C;&#x6240;&#x6709;&#x4E0D;&#x662F;&#x6570;&#x7EC4;
Type genericReturnType = genericityTest.getGenericReturnType();

9)注解的操作
注释的操作相对简单。如果我们想要阅读类、方法或字段上的批注,我们只需要获取您需要阅读的批注的修辞类、方法或字段。[en]The operation of annotations is relatively simple. If we want to read annotations on classes, methods, or fields, we only need to get the rhetorical classes, methods, or fields of the annotations you need to read.

让我们通过获取对该方法的评论来测试它:[en]Let’s test it by getting comments on the method:
在这里,我们仍然使用在本文开头创建的TestAnnotation注释,它只能放在方法上并保存到运行时。[en]Here we still use the TestAnnotation annotations we created at the beginning of the article, which can only be placed on the method and saved until run time.

public class AnnotationTest {

    @TestAnnotation("sml")
    public static void main(String[] args) {

        try {
            Class aClass = Class.forName("sml.annotation.AnnotationTest");
            Method main = aClass.getDeclaredMethod("main",String[].class);
            //&#x6839;&#x636E;&#x6211;&#x4EEC;&#x7684;main&#x65B9;&#x6CD5;&#x83B7;&#x53D6;main&#x65B9;&#x6CD5;&#x4E0A;&#x7684;&#x6CE8;&#x89E3;
            TestAnnotation declaredAnnotation = main.getDeclaredAnnotation(TestAnnotation.class);
            //&#x83B7;&#x53D6;&#x5230;&#x4ED6;&#x7684;&#x503C;
            String value = declaredAnnotation.value();
            System.out.println(value);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

注:如果我们需要获取类上的注解,只需要获取到类对象,然后.getDeclaredAnnotation()即可,其实不管是获取类上的注解还是字段上的注解都是一样的方法,关于有无Declared的方法,看到这里大家应该也有了解了。

最后,我们可能没有意识到注释在这里的重要作用。在接下来的文章中,我将写一篇关于手写的SpringMVC框架的博客,但当然它太简单了。如果您阅读这篇文章并自己编写它,我相信您对注释和反思都有足够的了解。[en]Finally, we may not realize the great role of annotations here. In the following article, I will write a blog about the handwritten SpringMVC framework, but of course it is too simple to be simple. If you read this article and write it on your own, I’m sure you all know enough about annotations and reflections.

Original: https://blog.csdn.net/weixin_45056780/article/details/105127722
Author: 世代农民
Title: java注解与反射的基本使用(这一篇就够了!)

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/6117/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

发表回复

登录后才能评论
免费咨询
免费咨询
扫码关注
扫码关注
联系站长

站长Johngo!

大数据和算法重度研究者!

持续产出大数据、算法、LeetCode干货,以及业界好资源!

2022012703491714

微信来撩,免费咨询:xiaozhu_tec

分享本页
返回顶部