从 JDK 5.0 開始, Java 添加了对元数据(MetaData) 的支持, 也就是 Annotation(注解)。

什么是Annotation,以及注解的作用?

三个主要的 Annotation:

  • @Override: 限定重写父类方法, 该注解仅仅能用于方法
  • @Deprecated: 用于表示某个程序元素(类, 方法等)已过时
  • @SuppressWarnings: 抑制编译器警告.

上面的注解,在我们平时的编程中都是能够看见的。比方定义一个Parent类和一个MyIterface的接口。用Child的子类去继承Parent并实现MyInterface.就能够看到

Parent

public class Parent {
public void m1(){ }
public void l1l1l1l1llll1ll1l1(){ }
}

MyInterface

public interface MyInterface {
void m2();
}

Child

Annotation 事实上就是代码里的特殊标记, 它用于替代配置文件,也就是说。传统方式通过配置文件告诉类怎样执行,有了注解技术后,开发者能够通过注解告诉类怎样执行。在Java技术里注解的典型应用是:能够通过反射技术去得到类里面的注解,以决定怎么去执行类。

掌握注解技术的要点:

  • 怎样定义注解
  • 怎样反射注解。并依据反射的注解信息,决定怎样去执行类

一、注解的基本知识

1、怎样定义注解

定义新的 Annotation 类型使用 @interface 关键字

public @interface 注解的名称{}

2、定义注解中的属性

注解属性的作用:原来写在配置文件里的信息,能够通过注解的属性进行描写叙述。

类型 属性名称() [default 默认值];

Annotation 的属性声明方式:String name();

属性默认值声明方式:String name() default “xxx”;

特殊属性value:假设注解中有一个名称value的属性,那么使用注解时能够省略value=部分,如@MyAnnotation(“xxx"),可是出现多个属性时,那就应该要写上value值,这样比較明白。

定义一个MyAnno1的注解。同一时候定义一个MyAnno2 ,MyAnno2 作为MyAnno1的一个属性。

public @interface MyAnno2 {
int num();
}
//全部定义的注解都是java.lang.annotation.Annotation的子类

//定义注解
public @interface MyAnno1 {
String name() default "";//注解的属性
int age() default 0;
// MyAnno2[] myann(); //属性还能够是注解。注解数组
String [] value() default "";
}

使用自己定义的注解

//使用自己定义的注解
public class UseMyAnno1 { // @MyAnno1(name = "abc", age = 19, myann = { @MyAnno2(num = 20),
// @MyAnno2(num = 200) }) //myann是一个注解数组。
// public void method() {
//
// } //@MyAnno1("abc") 就是给注解的value属性赋值
@MyAnno1(value={"def","ddd"},age=10)
public void method() { }
}

特别注意:类型必须是基本类型、String、Class、注解类型、枚举及以上类型的一维数组。

二、注解的反射

1、 AnnotationElement 接口

JDK 5.0 在 java.lang.reflect 包下新增了 AnnotationElement 接口, 该接口代表程序中能够接受凝视的程序元素,具有例如以下方法

  • T getAnnotation(Class clazz):得到指定的注解类型
  • Annotation[] getAnnotations():得到全部的注解类型
  • Annotation[] getDeclaredAnnotations():得到自己上面的直接的注解类型
  • boolean isAnnotationPresent(Class clazz):有没有指定的注解

Class、Method、Field、Constructor等都实现了该接口。

实例:编写一个自己的注解Anno1,在MyClass1中使用该注解,MyClass2继承MyClass1,这样,MyClass2也具有MyClass1上的注解,可是两者还是有区别的,看例如以下代码

package com.itheima.other.metaanno;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE,ElementType.METHOD})
@Documented
@Inherited
public @interface Anno1 { }

MyClass1

package com.itheima.other.metaanno;
/**
* 这是一个測试类
* @author wzhting
*
*/
@Anno1
public class MyClass1 { }

MyClass2

package com.itheima.other.metaanno;

import java.lang.annotation.Annotation;

public class MyClass2 extends MyClass1 {
public static void main(String[] args) {
Class clazz = MyClass2.class;
// Anno1 a1 = (Anno1) clazz.getAnnotation(Anno1.class);
// System.out.println(a1); Annotation ans[] = clazz.getDeclaredAnnotations();//获取直接存在的注解
for(Annotation a:ans)
System.out.println(a);
}
}

比方:推断Object这个类上面有没有MyAnn1的注解

Class clazz = Object.class;
Boolean b = clazz.isAnnotationPresent(MyAnn1.class);

2、注解的生命周期:

2.1 AnnotatedElement元注解

仅仅能用在注解上的注解,就是元注解。JDK中定义了例如以下元Annotation:

  • @Retention:

@Retention: 仅仅能用于修饰一个 Annotation 定义, 用于指定该 Annotation 能够保留的, @Rentention 包括一个 RetentionPolicy 类型的成员变量, 通过这个变量指定域。

  1. RetentionPolicy.CLASS: 编译器将把注解记录在 class 文件里. 当执行 Java 程序时, JVM 不会保留注解. 这是默认值
  2. RetentionPolicy.RUNTIME:编译器将把凝视记录在 class 文件里. 当执行 Java 程序时, JVM 会保留注解. 程序能够通过反射获取该凝视
  3. RetentionPolicy.SOURCE: 编译器直接丢弃这样的策略的凝视

  • @Target:指示注解能用在何处

    ElementType:指定注解用于修饰类的哪个成员. @Target 包括了一个名为 value。类型为ElementType的成员变量。看源代码可知有TYPE (Class,Interface), FIELD, METHOD, PARAMETER, ANNOTATION_TYPE等声明常量。

实例:自己定义注解类MyTest

首先定义两个实体类,用于单元測试分别为PersonDaoImpl 和測试类PersonDaoImplTest

PersonDaoImpl

package com.itheima.dao.impl;

public class PersonDaoImpl {
public void add(){
System.out.println("保存了");
}
public void del(){
System.out.println("执行了删除");
}
}

PersonDaoImplTest

package com.itheima.dao.impl;

import org.junit.Test;

public class PersonDaoImplTest {
private PersonDaoImpl dao = new PersonDaoImpl(); //測试方法:必须是public的;没有返回值;没有參数
@MyTest(timeout=1)//===>自己编写MyTest注解
public void testAdd() throws InterruptedException{
// Thread.sleep(100);
dao.add();
}
public void testDel(){
dao.del();
}
}

自己定义一个类MyTest,和JUnit的@Test类类似。

package com.itheima.dao.impl;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME)//编译时,JVM保留注解
@Target(ElementType.METHOD)//使用于方法。 public @interface MyTest {
long timeout() default -1;//没有时间限制。单位是毫秒
}

反射注解的方法及属性(重点)

通过反射技术,编写MyTestRunner 类,实现MyTest注解的功能。

package com.itheima.dao.impl;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method; public class MyTestRunner { public static void main(String[] args) throws Exception{
test1();
}
//反射注解的属性
private static void test2() throws IllegalAccessException,
InvocationTargetException, InstantiationException {
Class clazz = PersonDaoImplTest.class;
Method ms[] = clazz.getMethods();
for(Method m:ms){
MyTest myTest = m.getAnnotation(MyTest.class);//假设当前方法上面没有@MyTest注解。返回的是null
if(myTest!=null){
//执行该方法。推断是否超时
long time = System.currentTimeMillis();
m.invoke(clazz.newInstance(), null);
long actualUseTime = System.currentTimeMillis()-time;//实际耗时
//获取注解上配置的timeout属性的值
long planUserTime = myTest.timeout();
if(planUserTime>=0){
//说明用户指定了时间
if(actualUseTime>planUserTime)
throw new RuntimeException("超时");
}
}
}
}
//反射方法上面的注解 private static void test1() throws IllegalAccessException,
InvocationTargetException, InstantiationException {
//得到測试类的字节码
Class clazz = PersonDaoImplTest.class;
//得到全部的方法
Method ms[] = clazz.getMethods();
//推断方法上面有没有叫做@MyTest的注解
for(Method m:ms){
boolean b = m.isAnnotationPresent(MyTest.class);
System.out.println(m.getName()+":"+b);
//假设有:调用该方法
if(b)
m.invoke(clazz.newInstance(), null);
}
} /* testAdd:true
testDel:false
wait:false
wait:false
wait:false
equals:false
toString:false
hashCode:false
getClass:false
notify:false
notifyAll:false*/ }

下面两个了解就可以。

  • @Documented:用于指定被该元 Annotation 修饰的 Annotation 类将被 javadoc 工具提取成文档.
  • @Inherited:被它修饰的 Annotation 将具有继承性.假设某个类使用了被 @Inherited 修饰的 Annotation, 则其子类将自己主动具有该注解

三、servlet3.0 中的注解

在servlet3.0以后,就能够採用注解的方式代替web.xml文件里的servlet映射了

比方例如以下servlet

package com.itheima.servlet;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.Enumeration; import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebInitParam;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; @WebServlet(value = { "/servlet/ServletDemo1", "/servlet/ServletDemo11" }, initParams = {
@WebInitParam(name = "encoding", value = "UTF-8"),
@WebInitParam(name = "XXX", value = "YYY") })
public class ServletDemo1 extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
out.write("ServletDemo1<hr/>");
ServletConfig cfg = getServletConfig();
Enumeration e = cfg.getInitParameterNames();
while(e.hasMoreElements()){
String paramName = (String)e.nextElement();
out.write(paramName+"="+cfg.getInitParameter(paramName)+"<br/>");
}
} public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
} }

当然,在过滤器和监听器中,也一样能够採用注解的方法代替web.xml的配置。

JavaSE学习笔记--Item1 注解Annotation的更多相关文章

  1. Java学习笔记:注解Annotation

    annotation的概念 In the Java computer programming language, an annotation is a form of syntactic metada ...

  2. springmvc学习笔记(常用注解)

    springmvc学习笔记(常用注解) 1. @Controller @Controller注解用于表示一个类的实例是页面控制器(后面都将称为控制器). 使用@Controller注解定义的控制器有如 ...

  3. 学习笔记_J2EE_SpringMVC_03_注解配置_@RequestMapping用法

    @RequestMappingde的用法 摘要: 主要介绍注解@RequestMapping的用法 一.@RequestMapping 简介 在Spring MVC 中使用 @RequestMappi ...

  4. javaSE学习笔记(17)---锁

    javaSE学习笔记(17)---锁 Java提供了种类丰富的锁,每种锁因其特性的不同,在适当的场景下能够展现出非常高的效率.本文旨在对锁相关源码(本文中的源码来自JDK 8).使用场景进行举例,为读 ...

  5. javaSE学习笔记(16)---网络编程

    javaSE学习笔记(16)---网络编程 基本概念 如今,计算机已经成为人们学习.工作.生活必不可少的工具.我们利用计算机可以和亲朋好友网上聊天,也可以玩网游.发邮件等等,这些功能实现都离不开计算机 ...

  6. javaSE学习笔记(15) ---缓冲流、转换流、序列化流

    javaSE学习笔记(15) ---缓冲流.转换流.序列化流 缓冲流 昨天复习了基本的一些流,作为IO流的入门,今天我们要见识一些更强大的流.比如能够高效读写的缓冲流,能够转换编码的转换流,能够持久化 ...

  7. JavaSE学习笔记(14)---File类和IO流(字节流和字符流)

    JavaSE学习笔记(14)---File类和IO流(字节流和字符流) File类 概述 java.io.File 类是文件和目录路径名的抽象表示,主要用于文件和目录的创建.查找和删除等操作. 构造方 ...

  8. JavaSE学习笔记(13)---线程池、Lambda表达式

    JavaSE学习笔记(13)---线程池.Lambda表达式 1.等待唤醒机制 线程间通信 概念:多个线程在处理同一个资源,但是处理的动作(线程的任务)却不相同. 比如:线程A用来生成包子的,线程B用 ...

  9. JavaSE学习笔记(12)---线程

    JavaSE学习笔记(12)---线程 多线程 并发与并行 并发:指两个或多个事件在同一个时间段内发生. 并行:指两个或多个事件在同一时刻发生(同时发生). 在操作系统中,安装了多个程序,并发指的是在 ...

随机推荐

  1. Python之数据规整化:清理、转换、合并、重塑

    Python之数据规整化:清理.转换.合并.重塑 1. 合并数据集 pandas.merge可根据一个或者多个不同DataFrame中的行连接起来. pandas.concat可以沿着一条轴将多个对象 ...

  2. 联想 S5 Pro(L78041)免解锁BL 免rec 保留数据 ROOT Magisk Xposed 救砖 ZUI 5.0.123

    >>>重点介绍<<< 第一:本刷机包可卡刷可线刷,刷机包比较大的原因是采用同时兼容卡刷和线刷的格式,所以比较大第二:[卡刷方法]卡刷不要解压刷机包,直接传入手机后用 ...

  3. React Native组件的结构和生命周期

    React Native组件的结构和生命周期 一.组件的结构 1.导入引用 可以理解为C++编程中的头文件. 导入引用包括导入react native定义的组件.API,以及自定义的组件. 1.1 导 ...

  4. spark查看stage和tasks信息

    spark提供了web-ui接口.外部命令等多种方法监视spark程序的执行状态.利用spark的监视功能,可以方便的查看spark应用程序执行的状态,具体包括:1)stage和tasks列表信息  ...

  5. (转)Hibernate框架基础——映射普通属性

    http://blog.csdn.net/yerenyuan_pku/article/details/52739871 持久化对象与OID 对持久化对象的要求 提供一个无参的构造器.使Hibernat ...

  6. JMeter在linux上分布式压测步骤(二)

    哈喽,我又来了~ 前提:三台linux虚拟机,一台作为master,另外两台作为slave. 一.server端 1.修改1099端口,client和server通信的端口,可以不修改,默认就是109 ...

  7. JMeter在linux上分布式压测环境配置(一)

    环境配置 一.在Linux服务器先安装SDK 1.先从官网下载jdk1.8.0_131.tar.gz,l(linux版本,32位,64位根据系统来判断) 2.在/usr/目录下创建java文件夹,(当 ...

  8. CAD动态绘制样条线(网页版)

    在CAD设计时,需要绘制样条线,用户可以设置样条线线重及颜色等属性. 主要用到函数说明: _DMxDrawX::SendStringToExecuteFun 把命令当着函数执行,可以传参数.详细说明如 ...

  9. sql常用手法(二)

    drop,TRUNCATE和delete的区别 1.DROP删表,表结构将删了,当然数据也不存在了2.TRUNCATE和DELETE删数据,表结构还在3.DELETE可以带条件删除,TRUNCATE是 ...

  10. Gym - 101670F Shooting Gallery(CTU Open Contest 2017 区间dp)

    题目&题意:(有点难读...) 给出一个数字序列,找出一个区间,当删除这个区间中的两个相同的数字后,只保留这两个数字之间的序列,然后继续删除相同的数字,问最多可以实行多少次删除操作. 例如: ...