1.标注和注释
注释:用来解释说明程序的代码功能 不会编译到class字节码文件之中
标注:用来描述代码的代码 准确的来说是元数据 即是一种描述数据的数据 标注就是源代码的元数据
2.标注:
@Override
public String toString() {
return "This is String Representation of current object.";
}
上述代码中的@Override 标注告诉程序我在这重写了toString()方法 如果我的方法名错误系统会自动识别到这是重写的方法 提示我错误,这样减少了我的代码错误量 更好的帮助我们阅读 如果不写注解的话可能这个拼写错误就会误认为是其他的方法名这样会导致程序的错误不好纠正 难易更改
3.标注所属的类
Annotation是一种应用于类、方法、参数、变量、构造器及包声明中的特殊修饰符,它是一种由JSR-175标准选择用来描述元数据的一种工具
4.标注的分类
(1)编写文档:通过代码里标识的元数据生成文档
(2)代码分析:果果代码里标识的元数据对代码进行分析
(3)编译检查:通过代码里标识的元数据让编译器能实现基本的编译检查
5.常见的标注:
1.@Override 校验格式
2.@Deprecated 标记过时的方法或者类
3.@SuppressWarnnings 用于抑制编译器的警告
JDK1.8之后增加了:@Functionallnterface()这样的
@Override的源代码:
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
}
6.标注的详解:
(1)@Target:
说明了Annotation所修饰的对象范围,也就是我们这个注解是用在那个对象上面的:Annotation可被用于 packages、types(类、接口、枚举、Annotation类型)、类型成员(方法、构造方法、成员变量、枚举值)、方法参数和本地变量(如循环变量、catch参数)。在Annotation类型的声明中使用了target可更加明晰其修饰的目标。以下属性是多选状态,我们可以定义多个注解作用域
@Target({ElementType.METHOD,ElementType.FIELD}) | 定义多个注解作用域 |
@Target(ElementType.FIELD) | 单个的使用 |
CONSTRUCTOR | 构造方法声明 |
FIELD | 用于描述域也就是类属性之类的,字段声明(包括枚举常量) |
LOCAL_VARIABLE | 用于描述局部变量 |
METHOD | 用于描述方法 |
PACKAGE | 包声明 |
PARAMETER | 参数声明 |
TYPE | 类、接口(包括注释类型)或枚举声明 |
ANNOTATION_TYPE | 注释类型声明,只能用于注释注解 |
(2)@Retention
定义了该Annotation被保留的时间长短:某些Annotation仅出现在源代码中,而被编译器丢弃;而另一些却被编译在class文件中;编译在class文件中的Annotation可能会被虚拟机忽略,而另一些在class被装载时将被读取(请注意并不影响class的执行,因为Annotation与class在使用上是被分离的)。使用这个meta-Annotation可以对 Annotation的“生命周期”限制。来源于java.lang.annotation.RetentionPolicy的枚举类型值:
(1).SOURCE:在源文件中有效(即源文件保留)编译成class文件将舍弃该注解。
(2).CLASS:在class文件中有效(即class保留) 编译成dex文件将舍弃该注解。
(3).RUNTIME:在运行时有效(即运行时保留) 运行时可见。
也就是说注解处理器能处理这三类的注解,我们通过反射的话只能处理RUNTIME类型的注解.
官方解释:指示注释类型的注释要保留多久。如果注释类型声明中不存在 Retention 注释,则保留策略默认为 RetentionPolicy.CLASS。只有元注释类型直接用于注释时,Target 元注释才有效。如果元注释类型用作另一种注释类型的成员,则无效。
(3)@Documented
指示某一类型的注释将通过 javadoc 和类似的默认工具进行文档化。应使用此类型来注释这些类型的声明:其注释会影响由其客户端注释的元素的使用。如果类型声明是用 Documented 来注释的,则其注释将成为注释元素的公共 API 的一部。Documented是一个标记注解,没有成员。
(4)@Inherited
元注解是一个标记注解,@Inherited阐述了某个被标注的类型是被继承的。如果一个使用了@Inherited修饰的annotation类型被用于一个class,则这个annotation将被用于该class的子类。 注意:@Inherited annotation类型是被标注过的class的子类所继承。类并不从它所实现的接口继承annotation,方法并不从它所重载的方法继承annotation。当@Inherited annotation类型标注的annotation的Retention是RetentionPolicy.RUNTIME,则反射API增强了这种继承性。如果我们使用java.lang.reflect去查询一个@Inherited annotation类型的annotation时,反射代码检查将展开工作:检查class和其父类,直到发现指定的annotation类型被发现,或者到达类继承结构的顶层。
官方解释:指示注释类型被自动继承。如果在注释类型声明中存在 Inherited 元注释,并且用户在某一类声明中查询该注释类型,同时该类声明中没有此类型的注释,则将在该类的超类中自动查询该注释类型。此过程会重复进行,直到找到此类型的注释或到达了该类层次结构的顶层 (Object) 为止。如果没有超类具有该类型的注释,则查询将指示当前类没有这样的注释。
注意,如果使用注释类型注释类以外的任何事物,此元注释类型都是无效的。还要注意,此元注释仅促成从超类继承注释;对已实现接口的注释无效。
(5)@Repeatable
Repeatable可重复性,Java 1.8新特性,其实就是把标注的注解放到该元注解所属的注解容器里面。
7.自定义标注
标注的定义要求:
- 注解方法不能带有参数。
- 注解方法返回值类型限定为:基本类型、String、Enums、Annotation或者这些类型的数组。
- 注解方法可以有默认值。
- 注解本身能够包含元注解,元注解被用来注解其他注解。
注解实例:
//我写的标注, 用来给方法加标注, 不能用在类,属性, 构造方法上
@Target({METHOD})
//我写的标注, 请保留在类对象中, 不要在编译和类加载时擦除
@Retention(RUNTIME)
@interface Test{
String value() default "testcase 1";
}
测试用到的类:
class A{
@Test
public void m1(String a){
System.out.println("A m1 "+a);
}
@Test("testcase 2")
public void m2(String a){
System.out.println("A m2 "+a);
}
public void m3(String a){
System.out.println("A m3 "+a);
}
@Test("testcase 3")
public void m4(String a){
System.out.println("A m4 "+a);
}
}
class B{
@Test("testcase 4")
public void bm1(String a){
System.out.println("B bm1 "+a);
}
public void bm2(String a){
System.out.println("B bm2 "+a);
}
@Test("testcase 5")
public void bm3(String a){
System.out.println("B bm3 "+a);
}
}
class C{
public void methoda(String s){
System.out.println("C methoda "+s);
}
@Test("Liucy")
public void methodb(String s){
System.out.println("C methodb "+s);
}
@Test("Wangyx")
public void methodc(String s){
System.out.println("C methodc "+s);
}
@Test
public void methodd(String s){
System.out.println("C methodd "+s);
}
}
主函数测试类:
package day31;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import java.lang.reflect.Method;
public class TestAnnotation {
public static void main(String[] args) throws Exception {
// A a = new A();
// a.m1("testcase 1");
// a.m2("testcase 2");
// a.m4("testcase 3");
test(A.class);
// B b = new B();
// b.bm1("testcase 4");
// b.bm3("testcase 5");
test(B.class);
test(C.class);
}
static <T> void test(Class<T> c) throws Exception{
Object o = c.newInstance();
Method[] ms = c.getDeclaredMethods();
for(Method m : ms){
if (m.isAnnotationPresent(Test.class)){
Test t = m.getAnnotation(Test.class);
String parameter = t.value();
m.invoke(o , parameter);
}
}
}
}
Best Wish you!