Java 注解(Annotation)

Java 注解(Annotation)文章目录Annotation工作方式JDK5内建Annotation限定Override父类方法@Override标示方法为Deprecated@Deprectated抑制编译程序警告@SuppressWarnings自定义Annotation类型Annotation高级特性Annotation工作方式从Java5.0版发布以来,5.0平台提供了一个正式的annoatation功能:允许开…

大家好,又见面了,我是你们的朋友全栈君。

Annotation工作方式

从Java5.0版发布以来,5.0平台提供了一个正式的annoatation功能:允许开发者定义、使用自己的annotation类型。此功能由一个定义annotation声明的语法,读取annotation的API,一个使用annotation修饰的class文件,一个annotation处理工具(apt)组成。

annotation并不直接影响代码语义,但是它能够工作的方式被看作类似程序的工具或者类库,它会反过来对正在运行的程序语义有所影响。
annotation可以从源文件、class文件或者以在运行时反射的多种方式被读取。

JDK5 内建Annotation

Java 注解(Annotation):

限定Override父类方法@Override

java.langOverride是个Marker annotation
用于标示的Annotation,Annotation名称本身即表示了要给工具程序的信息
a) Override 注解表示子类要重写(override) 父类的对应方法。

package sixtyNineth;

public class OverrideTest { 
   

	@Override
	public String toString() { 
   
		return "This is OverrideTest";
	}
	
	public static void main(String[] args) { 
   
		OverrideTest test = new OverrideTest();
		
		System.out.println(test);
	}
}

结果是:
This is OverrideTest

标示方法为Deprecated @Deprectated

对编译程序说明某个方法已经不建议使用,即该方法是过时的。
java.lang.Deprecated也是个Marker annotation
Deprecated这个名称在告知编译程序,被@Deprecated标示的方法是一个不建议被使用的方法
b) Deprecated 注解表示方法是不建议被使用的。

package sixtyNineth;

import java.sql.Date;

public class DeprecatedTest { 
   

	@Deprecated
	public void doSomething() { 
   
		System.out.println("do something");
	}

	public static void main(String[] args) { 
   
		
		DeprecatedTest test = new DeprecatedTest();
		
		test.doSomething();
		
		
		
		/*Date date = new Date(0); System.out.println(date.toLocaleString());*/
	}
}

结果是:
do something

抑制编译程序警告@SuppressWarnings

对编译程序说明某个方法中若有警告讯息,则加以抑制
c) SuppressWarnings 注解表示抑制警告。

package sixtyNineth;

import java.util.Date;
import java.util.Map;
import java.util.TreeMap;

public class SuppressWarningTest { 
   

	@SuppressWarnings({ 
    "unchecked", "rawtypes" })
	public static void main(String[] args) { 
   
		Map map = new TreeMap();
		
		map.put("hello", new Date());
		
		System.out.println(map.get("hello"));
	}
}

结果是:
Sun Jan 13 19:59:06 CST 2019

自定义Annotation类型

定义Marker Annotation,也就是Annotation名称本身即提供信息对于程序分析工具来说,主要是检查是否有Marker Annotation的出现,并作出对应的动作。

自定义注解:当注解中的属性名为 value 时,在对其赋值时可以不指定属性的名称
而直接写上属性值即可;除了 value 以外的其他值都需要使用 name=value 这种赋值
方式,即明确指定给谁赋值。

package sixtyNineth;

public @interface AnnotationTest { 
   
	
	String value1();

}

package sixtyNineth;

public @interface AnnotationTest1 { 
   

	String value();
}

package sixtyNineth;

@AnnotationTest(value1 = "hello")
public class AnnotationUsage { 
   
	
	@AnnotationTest1("world")
	public void method() { 
   
		System.out.println("usage of annotation");
	}
	
	public static void main(String[] args) { 
   
		AnnotationUsage usage = new AnnotationUsage();
		
		usage.method();
	}

}

结果是:
usage of annotation

Single-value annotation

value成员设定默认值,用”default”关键词
数组方式的使用
枚举在Annotation中的应用

package sixtyNineth;

public @interface AnnotationTest1 { 
   

	String[] value1() default "hello";
	EnumTest value2();
}

enum EnumTest{ 
   
	Hello, World, Welcome
}

package sixtyNineth;

@AnnotationTest1(value2 = EnumTest.Welcome, value1 = "world")
public class AnnotationUsage { 
   
	
	@AnnotationTest1(value1 = { 
   "hello","haha"}, value2 = EnumTest.Hello)
	public void method() { 
   
		System.out.println("usage of annotation");
	}
	
	public static void main(String[] args) { 
   
		AnnotationUsage usage = new AnnotationUsage();
		
		usage.method();
	}

}

使用@interface自定义Annotation型态时,实际上是自动继承了java.lang.annotation.Annnotation接口由编译程序自动为您完成其它产生的细节,在定义Annotation型态时,不能继承其他的Annotation型态或者接口。
java.lang.annotation
Interface Annotation

The common interface extended by all annotation types. Note that an interface that manually extends this one does not define an annotation type. Also note that this interface does not itself define an annotation type.

当 我 们 使 用 @interface 关 键 字 定 义 一 个 注 解 时 , 该 注 解 隐 含 地 继 承 了java.lang.annotation.Annotation 接口;如果我们定义了一个接口,并且让该接口继承自 Annotation,那么我们所定义的接口依然还是接口而不是注解; Annotation 本身是接口而不是注解。 (可以与 Enum 类比。)

定义Annotation型态时也可以使用包来管理类别方式类同于类的导入功能。

告知编译程序如何处理@Retention

java.lang.annotation.Retention型态可以在您定义Annotation型态时,指示编译程序该如何对待您的自定义的Annotation型态。
==预设上编译程序会将Annotation信息留在.class档案中,==但是不被虚拟机读取,而仅用于编译程序或工具程序运行时提供信息。
在使用Retention型态时,需要提供java.lang.annotation.RetentionPolicy的枚举型态Package java.lang.annotation;

public enum RetentionPolicy
{ 
   
    SOURCE,//编译程序处理完Annotation信息后就完成任务
    CLASS,//编译程序将Annotation储存于class档中,缺省,不由VM读入
    RUNTIME //编译程序将Annotation储存于class档中,可由VM读入,通过反射的方式读取到
}

RetentionPolicy为SOURCE的例子是@SuppressWarnings
仅在编译时期告知编译程序来抑制警告,所以不必将这个信息储存于.class档案
RetentionPolicy为RUNTIME的时机,可以像是您使用Java设计一个程序代码分析工具,您让VM能读出Annotation信息,以便在分析程序时使用。
搭配反射(Reflectiong)机制,就可以达到这个目的

package Seventieth.First;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.CLASS)
public @interface MyAnnotation { 
   

    String hello() default "Matthew";

    String world();
}

package Seventieth.First;

@MyAnnotation(hello = "beijing", world = "shanghai")
public class MyTest { 
   

    @MyAnnotation(hello = "tianjing", world = "shangdi")
    @Deprecated
    @SuppressWarnings("unchecked")
    public void output(){ 
   
        System.out.println("output something");
    }

    public static void main(String[] args) { 
   
        MyTest myTest = new MyTest();

        myTest.output();
    }

}

java.lang.reflect.AnnotatedElement接口
public Annotation getAnnotation(Class annotationType);
public Annotation[] getAnnotations();
public Annotation[] getDeclaredAnnotations();
public boolean isAnnotationPresent(Class annotationType);
Class、Constructor、Field、Method、Package等类别,都实现了AnnotationElement接口

package Seventieth.First;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {

    String hello() default "Matthew";

    String world();
}

package Seventieth.First;

@MyAnnotation(hello = "beijing", world = "shanghai")
public class MyTest { 
   

    @MyAnnotation(hello = "tianjing", world = "shangdi")
    @Deprecated
    @SuppressWarnings("unchecked")
    public void output(){ 
   
        System.out.println("output something");
    }

   /* public static void main(String[] args) { MyTest myTest = new MyTest(); myTest.output(); }*/

}

package Seventieth.First;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;

public class MyReflection {
    public static void main(String[] args) throws  Exception{

        MyTest myTest = new MyTest();

        Class<MyTest> c = MyTest.class;

        Method method = c.getMethod("output", new Class[]{});

        if(method.isAnnotationPresent(MyAnnotation.class)){
            method.invoke(myTest, new Object[]{});

            MyAnnotation myAnnotation = method.getAnnotation(MyAnnotation.class);

            String hello = myAnnotation.hello();
            String world = myAnnotation.world();

            System.out.println(hello + "," + world);
        }

        Annotation[] annotations = method.getAnnotations();

        for(Annotation annotation : annotations){
            System.out.println(annotation.annotationType().getName());
        }

    }
}

结果是:
output something
tianjing,shangdi
Seventieth.First.MyAnnotation
java.lang.Deprecated

当我们在@Retention(RetentionPolicy.RUNTIME)不用RUNTIME而用CLASS和SOURCE时,运行结果为空,因为注解存在了class文件当中,但是,VM不会反射读取出来,method.isAnnotationPresent(MyAnnotation.class)为false所以没有输出。
@Retention(RetentionPolicy.SOURCE)
因为SuppressWarnings的RetentionPolicy为SOURCE

限定annotation使用对象@Target

使用java.lang.annotation.Target可以定义其使用的时机,在定义时要指定java.lang.annotation.ElementType的枚举值之一
package java.lang.annotation;
public enum ElementType{

TYPE,//适用class,interface,enum
FIELD,//适用field
METHOD,//适用method
PARAMETER,//适用method上的parameter
CONSTRUCTOR,//适用costructor
LOCAL_VARIABLE,//适用局部变量
ABBOTATION_TYPE,//适用annotation型态
PACKAGE//适用package
}

package Seventieth.First;

import java.lang.annotation.ElementType;
import java.lang.annotation.Target;

@Target(ElementType.METHOD)
public @interface MyTarget { 
   

    String value();
}

package Seventieth.First;

public class MyTargetTest { 
   

    @MyTarget("hello")
    public void doSomething(){ 
   

        System.out.println("hello world");

    }

}

如果把 @MyTarget(“hello”)放在类上面就会报错’@MyTarget’ not applicable to type,我们把
@Target(ElementType.METHOD)改为@Target(ElementType.TYPE)就不会报错了

要求为API文件@Documented

想要在使用者制作JavaDoc文件的同时,也一并将Annotation的讯息加入至API文件中使用java.lang.annotation.Documented

package Seventieth.First;

public @interface DocumentedAnnotation {
    String hello();
}

package Seventieth.First;

public class DocumentedTest {
    @DocumentedAnnotation(hello = "welcome")
    public void method(){
        System.out.println("hello world");
    }
}

生成java帮助文档在Tool》Generate JavaDoc
然后在弹出的界面点击Output directory后的按钮选择文档生成路径
接下来在底部的Locale输入框配置语言和编码集,如下图所示,语言用zh_CN,代表中文
在这里插入图片描述
点击ok生成帮助文档
在这里插入图片描述
这就是我生成的java帮助文档,点击DocumentTest拉到最下面有方法详细资料
在这里插入图片描述
我们将DoucumentedAnnotation.java更改一下

package Seventieth.First;

import java.lang.annotation.Documented;

@Documented
public @interface DocumentedAnnotation { 
   
    String hello();
}

再次生成帮助文档,我们发现发发详细资料变成如下图所示的样子

在这里插入图片描述

子类是否继承父类@Inherited

预设上夫类别中断Annotation并不会被继承至子类别中,可以在定义Annotation型态时加上java.lang.annotation.Inherited型态的Annotation

通过JUnit深入理解反射与注解的使用方式与场景

现在项目中导入jar包

package Seventieth.Secound;

import junit.framework.TestCase;

public class Test extends TestCase { 
   


    public void testAdd(){ 
   
        System.out.println("hello world");
    }

    public void testSubtract(){ 
   
        System.out.println("welcome");
    }

}


结果是:
hello world
welcome

方法必须以test开头,JUnit我们学过反射后应该大致了解其思路,首先获得这个类的Class对象,然后获得其所有的方法,存入Method[]然后遍历每一个方法,getName获得方法名,如果是以test开头就通过method.invoke执行这个方法

JUnit(3.8、 4.x): Keep the bar green to keep the code clean.

package Seventieth.Secound;

import org.junit.Test;

public class Test2 { 
   
    @Test
    public void hello(){ 
   
        System.out.println("hello world");
    }
}

JUnit4 的执行的一般流程:
a) 首先获得待测试类所对应的 Class 对象。
b) 然后通过该 Class 对象获得当前类中所有 public 方法所对应的 Method 数组。
c) 遍历该 Method 数组,取得每一个 Method 对象
d) 调用每个 Method 对象的 isAnnotationPresent(Test.class)方法,判断该方法是否被 Test
注解所修饰。
e) 如果该方法返回 true,那么调用 method.invoke()方法去执行该方法,否则不执行。

单元测试不是为了证明你是对的,而是证明你没有错误。
Writing Secure Code(编写安全的代码): Input is evil。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/156667.html原文链接:https://javaforall.net

赞 (0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • blob视频如何下载_blob加密视频下载

    blob视频如何下载_blob加密视频下载前言网页上有些视频是直接给的视频地址,那么很多浏览器都有插件进行视频下载,比如猎豹浏览器的:浏览器中有些视频是通过blob:https://baike.baidu.com/bf834217-9442-4c98-9ef6-0bd5f3408a4e的形式给出的。blob后面的网址不能直接访问。这是分片段进行加载的。。。比如百度百科搜索中的视频:离子液体这篇博客教你如何下载此类视频。准…

    2022年10月26日
  • 如何理解java方法的传值和传引用的参数传递方式(基本数据类型和引用类型)

    结论:1)当使用基本数据类型作为方法的形参时,在方法体中对形参的修改不会影响到实参的数值2)当使用引用数据类型作为方法的形参时,若在方法体中修改形参指向的数据内容,则会对实参变量的数值产生影响,因为形参变量和实参变量共享同一块堆区;3)当使用引用数据类型作为方法的形参时,若在方法体中修改形参变量的指向,此时不会对实参变量的数值产生影响,因此形参变量和实参变量分别指向不同的堆区例一:基本数据类型作为形参,运行结果不改变实参publicclassMain{publicstatic

    2022年4月14日
  • mt4编程语言 c语言,MT4编程之MQL4编程语言介绍[通俗易懂]

    mt4编程语言 c语言,MT4编程之MQL4编程语言介绍[通俗易懂]语言介绍MetaQuotesLanguage4(MQL4)是一种新的内置型程序用来编写交易策略。这种语言可以创建你自己的智能交易,使自己的交易策略能够完全自动地执行。而且,MQL4还能自定义客户指标,脚本和数据库。内包含了大量可以分析当前及历史报价所必须的函数,以及一些基本的运算和逻辑操作。并内置了一些基本的指标和操作命令。MetaEditor4集合了编写MQL4程序代码的各种语句,它…

    2022年5月15日
  • Java零基础好学吗?Java该怎么学?

    Java零基础好学吗?Java该怎么学?Java零基础好学吗?Java该怎么学?在IT行业中,Java开发工程师是一个很吃香的职业,薪资水平也是几乎过万,许多人想转行Java开发,但又担心零基础能不能学会,学起来有多难,如果是零基础自学Java的话是比较困难的,学Java难不难取决于学习方法的选择和努力程度。今天就来讲讲Java零基础好学吗?Java该怎么学?Java学习路线:第一阶段:Java基础语法内容:运行环境、关键字、数据类型、运算符、方法、条件结构、循环结构、方法重载、数组。第二阶段:面向对象和封装内容:面向对象、thi

    2022年7月7日
  • windows net 命令详解「建议收藏」

    windows net 命令详解「建议收藏」综合了WINDOWS98,WINDOWSWORKSTATION和WINDOWSSERVER三个操作系统关于NET命令的解释,希望可以全面一些。先说一些:(1)NET命令是一个命令行命令。(2)管理网络环境、服务、用户、登陆。。。。等本地信息(3)WIN98,WINWORKSTATION和WINNT都内置了NET命令。(4)但WIN98的NET命令和WO

    2022年5月28日
  • 思维导图整理大厂面试高频数组26: 合并区间中详解lambada表达式和toArray()用法, 力扣56

    思维导图整理大厂面试高频数组26: 合并区间中详解lambada表达式和toArray()用法, 力扣56此专栏文章是对力扣上算法题目各种方法的总结和归纳,整理出最重要的思路和知识重点并以思维导图形式呈现,当然也会加上我对导图的详解.目的是为了更方便快捷的记忆和回忆算法重点(不用每次都重复看题解),毕竟算法不是做了一遍就能完全记住的.所以本文适合已经知道解题思路和方法,想进一步加强理解和记忆的朋友,并不适合第一次接触此题的朋友(可以根据题号先去力扣看看官方题解,然后再看本文内容).关于本专栏所有题目的目录链接,刷算法题目的顺序/注意点/技巧,以及思维导图源文件问题请点击此链接.想进大厂.

    2022年5月14日

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号