admin管理员组文章数量:1029569
注解1
注解是干什么用的?
注解(Annotation),我接触的时候经常会把它和一个听起来、看起来都很像的东西:注释(annotation)放在一起比较。对,“注解”和“注释”的英文都叫“annotation”,这怎么可能不让人混淆?
我最先接触到的注解为“@Override”,它就是用来提醒:下面这个方法是对一个已经存在的方法的重写。如果你把这个注解从代码中删掉,你会发现,你的程序一样正常运行,没有任何影响,就好像这玩意像注释一样被完全无视了(前提是你的这个代码确实没写错)。所以我一度觉得这玩意就是长得好看有逼格的注释。但是后面接触到web编程,用到了spring相关框架,发现代码中到处都是注解,并且这个时候注解和程序的正常运行直接挂钩,有些注解删了真的会影响程序运行。这么看来,注解和注释还是有不小的差别的。
先说结论:注解的作用是标记,但也仅仅只是标记。注解只是说,我给这个元素(类也好、属性也好、方法也好等等)打上了一个特定的记号,而至于怎么处理这些被标记的元素,注解是不管的,Java标准也不会做规定。这些被标记的元素由对应的具体程序做处理。可能是编译器处理,比如编译器会检查被“@Override”标记的方法是不是真的是重写的,如果不是就报错;也可能是由用户编写的程序在运行时处理,比如Spring框架中的各种注解,它们就由Spring框架进行处理。具体是哪一种,取决于注解的生命周期。
以网络游戏做类比的话,就像是你的队友“标记了一个目标”,你们团队的所有人都能看见这个标记。但是怎么处理被标记的目标?是远离?是靠近?是群起而攻之?或者干脆直接无视就当没看见?这个由玩家决定,游戏本身不做要求。而这个目标头上的标记,也仅仅起到一个提醒的作用。
PS:应该不会有哪个游戏丧心病狂到给敌人打个标记它就开始自动掉血吧。
简单例子
还是以我们最经常用到的注解:@Override为例子。这个注解我们自己写的时候可能都注意不到,大部分IDE会帮我们自动加上。先定义一个Person类,其中有一个hello方法;再定义一个Student类继承Person类,并重写hello方法。
代码语言:java复制public class Person {
public void hello() {
System.out.println("Person say hello");
}
}
代码语言:java复制public class Student extends Person{
@Override
public void hello() {
System.out.println("Student say hello");
}
}
我编写代码使用的是IDEA,编写Student类时会自动加上Override注解,当然你把它删了对程序也没有影响,就像网络游戏不打标记照样能玩一样。Override注解的作用体现在,比如你写的时候手滑误触了键盘,把Student类的hello函数写成了“Hello”函数,那在编译的时候,java编译器(这里用的是javac)就会报错:
代码语言:txt复制java: 方法不会覆盖或实现超类型的方法
如果没有这个注解,你会在运行中才会发现这个问题,因为把Student类中的hello方法名写错从语法本身来说没有任何问题,所以它一定能通过编译进入运行期。众所周知,问题暴露的阶段越早,定位和解决的成本越低。
简单认识
我们看看Override注解的定义:
代码语言:java复制package java.lang;
import java.lang.annotation.*;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}
注解的定义乍一眼看上去有点像定义接口,只是interface关键词前面多了一个“@”。除此以外,Override的定义上,还有两个注解,并且这个注解还带参数。注解带参数的问题咱们之后再说,先说说这两个注解是干什么用的。
打在注解定义头上的注解,叫元注解,也就是“注解的注解”。Java标准库已经定义了一些元注解,我们只需要使用元注解,通常不需要自己去编写元注解。元注解用于给注解打上标记,让对应的程序知道该怎么处理这个注解本身。
PS:“元XX”往往代表的是“XX的XX”,这么理解一般不会出错。
PPS:“元宇宙”不算。
元注解:Target
一个注解能够标记什么样的元素,由Target元注解说了算。Override的Target元注解参数为ElementType.METHOD,代表Override注解只能用于标记方法(method)。ElementType是枚举类型,完整的定义太长了我就不搬运到这里了。这里只举例几个常用的枚举值:
代码语言:java复制TYPE // 类或者接口
FIELD // 属性
METHOD // 方法
PARAMETER // 方法参数
CONSTRUCTOR // 构造方法
如果你有一定的叛逆精神,就是不想按照Target的限制使用注解,那编译器可能会不太高兴。比如我就想把Override注解标记到类上:
代码语言:java复制@Override
public class Student extends Person{
public void hello() {
System.out.println("Student say hello");
}
}
那编译器也不会惯着你:
代码语言:txt复制java: 注释类型不适用于该类型的声明
元注解:Retention
Retention元注解决定了这个注解的生命周期,说的通俗一点,决定了这个注解能活到什么时候。Java程序从编写到运行有三个阶段:Java源代码阶段-》编译后的字节码阶段-》虚拟机上的运行阶段。而巧了,Retention元注解的参数类型:RetentionPolicy,作为枚举类型,其三个枚举值正好对应这三个阶段:
代码语言:java复制public enum RetentionPolicy {
/**
* Annotations are to be discarded by the compiler.
*/
SOURCE,
/**
* Annotations are to be recorded in the class file by the compiler
* but need not be retained by the VM at run time. This is the default
* behavior.
*/
CLASS,
/**
* Annotations are to be recorded in the class file by the compiler and
* retained by the VM at run time, so they may be read reflectively.
*
* @see java.lang.reflect.AnnotatedElement
*/
RUNTIME
}
Override注解的Retention元注解参数为RetentionPolicy.SOURCE,从上面的代码注释中也能看出来,Override在编译器检查后就直接丢掉了,不会被带进字节码文件中。我们可以查看下Student类编译出来的字节码文件(由IDEA反编译获得):
代码语言:java复制//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
public class Student extends Person {
public Student() {
}
public void hello() {
System.out.println("Student say hello");
}
}
可以看到字节码反编译出来的代码中,Override注解已经消失了。
元注解只有这两个吗?注解的另外两个生命周期是怎么回事?带参数的注解又是干嘛的?下次再说。
注解1
注解是干什么用的?
注解(Annotation),我接触的时候经常会把它和一个听起来、看起来都很像的东西:注释(annotation)放在一起比较。对,“注解”和“注释”的英文都叫“annotation”,这怎么可能不让人混淆?
我最先接触到的注解为“@Override”,它就是用来提醒:下面这个方法是对一个已经存在的方法的重写。如果你把这个注解从代码中删掉,你会发现,你的程序一样正常运行,没有任何影响,就好像这玩意像注释一样被完全无视了(前提是你的这个代码确实没写错)。所以我一度觉得这玩意就是长得好看有逼格的注释。但是后面接触到web编程,用到了spring相关框架,发现代码中到处都是注解,并且这个时候注解和程序的正常运行直接挂钩,有些注解删了真的会影响程序运行。这么看来,注解和注释还是有不小的差别的。
先说结论:注解的作用是标记,但也仅仅只是标记。注解只是说,我给这个元素(类也好、属性也好、方法也好等等)打上了一个特定的记号,而至于怎么处理这些被标记的元素,注解是不管的,Java标准也不会做规定。这些被标记的元素由对应的具体程序做处理。可能是编译器处理,比如编译器会检查被“@Override”标记的方法是不是真的是重写的,如果不是就报错;也可能是由用户编写的程序在运行时处理,比如Spring框架中的各种注解,它们就由Spring框架进行处理。具体是哪一种,取决于注解的生命周期。
以网络游戏做类比的话,就像是你的队友“标记了一个目标”,你们团队的所有人都能看见这个标记。但是怎么处理被标记的目标?是远离?是靠近?是群起而攻之?或者干脆直接无视就当没看见?这个由玩家决定,游戏本身不做要求。而这个目标头上的标记,也仅仅起到一个提醒的作用。
PS:应该不会有哪个游戏丧心病狂到给敌人打个标记它就开始自动掉血吧。
简单例子
还是以我们最经常用到的注解:@Override为例子。这个注解我们自己写的时候可能都注意不到,大部分IDE会帮我们自动加上。先定义一个Person类,其中有一个hello方法;再定义一个Student类继承Person类,并重写hello方法。
代码语言:java复制public class Person {
public void hello() {
System.out.println("Person say hello");
}
}
代码语言:java复制public class Student extends Person{
@Override
public void hello() {
System.out.println("Student say hello");
}
}
我编写代码使用的是IDEA,编写Student类时会自动加上Override注解,当然你把它删了对程序也没有影响,就像网络游戏不打标记照样能玩一样。Override注解的作用体现在,比如你写的时候手滑误触了键盘,把Student类的hello函数写成了“Hello”函数,那在编译的时候,java编译器(这里用的是javac)就会报错:
代码语言:txt复制java: 方法不会覆盖或实现超类型的方法
如果没有这个注解,你会在运行中才会发现这个问题,因为把Student类中的hello方法名写错从语法本身来说没有任何问题,所以它一定能通过编译进入运行期。众所周知,问题暴露的阶段越早,定位和解决的成本越低。
简单认识
我们看看Override注解的定义:
代码语言:java复制package java.lang;
import java.lang.annotation.*;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}
注解的定义乍一眼看上去有点像定义接口,只是interface关键词前面多了一个“@”。除此以外,Override的定义上,还有两个注解,并且这个注解还带参数。注解带参数的问题咱们之后再说,先说说这两个注解是干什么用的。
打在注解定义头上的注解,叫元注解,也就是“注解的注解”。Java标准库已经定义了一些元注解,我们只需要使用元注解,通常不需要自己去编写元注解。元注解用于给注解打上标记,让对应的程序知道该怎么处理这个注解本身。
PS:“元XX”往往代表的是“XX的XX”,这么理解一般不会出错。
PPS:“元宇宙”不算。
元注解:Target
一个注解能够标记什么样的元素,由Target元注解说了算。Override的Target元注解参数为ElementType.METHOD,代表Override注解只能用于标记方法(method)。ElementType是枚举类型,完整的定义太长了我就不搬运到这里了。这里只举例几个常用的枚举值:
代码语言:java复制TYPE // 类或者接口
FIELD // 属性
METHOD // 方法
PARAMETER // 方法参数
CONSTRUCTOR // 构造方法
如果你有一定的叛逆精神,就是不想按照Target的限制使用注解,那编译器可能会不太高兴。比如我就想把Override注解标记到类上:
代码语言:java复制@Override
public class Student extends Person{
public void hello() {
System.out.println("Student say hello");
}
}
那编译器也不会惯着你:
代码语言:txt复制java: 注释类型不适用于该类型的声明
元注解:Retention
Retention元注解决定了这个注解的生命周期,说的通俗一点,决定了这个注解能活到什么时候。Java程序从编写到运行有三个阶段:Java源代码阶段-》编译后的字节码阶段-》虚拟机上的运行阶段。而巧了,Retention元注解的参数类型:RetentionPolicy,作为枚举类型,其三个枚举值正好对应这三个阶段:
代码语言:java复制public enum RetentionPolicy {
/**
* Annotations are to be discarded by the compiler.
*/
SOURCE,
/**
* Annotations are to be recorded in the class file by the compiler
* but need not be retained by the VM at run time. This is the default
* behavior.
*/
CLASS,
/**
* Annotations are to be recorded in the class file by the compiler and
* retained by the VM at run time, so they may be read reflectively.
*
* @see java.lang.reflect.AnnotatedElement
*/
RUNTIME
}
Override注解的Retention元注解参数为RetentionPolicy.SOURCE,从上面的代码注释中也能看出来,Override在编译器检查后就直接丢掉了,不会被带进字节码文件中。我们可以查看下Student类编译出来的字节码文件(由IDEA反编译获得):
代码语言:java复制//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
public class Student extends Person {
public Student() {
}
public void hello() {
System.out.println("Student say hello");
}
}
可以看到字节码反编译出来的代码中,Override注解已经消失了。
元注解只有这两个吗?注解的另外两个生命周期是怎么回事?带参数的注解又是干嘛的?下次再说。
本文标签: 注解1
版权声明:本文标题:注解1 内容由热心网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://it.en369.cn/jiaocheng/1747591320a2186963.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论