Java 8 新特性:扩展注解(类型注解和重复注解) ——诺诺"涂鸦"记忆

----------   诺诺学习技术交流博客、期待与您交流!  
 ----------

详情请查看:http://blog.csdn.net/sun_promise 

注解

(注:先回顾下JDK1.5版本出现的注解 ,然后再解释JDK 8的注解 更新内容。)

一.注解(JDK1.5)

1.注解(@)

注解就相当于一种标记,在程序中加了注解就等于为程序加了某种标记。(JDK1.5新特性)

2.作用:

告诉javac编译器或者java开发工具……向其传递某种信息,作为一个标记。

3.了解注解:

一个注解就是一个类。

标记可以加在包、类、字段、方法,方法参数以及局部变量上。可以同时存在多个注解。

每一个注解结尾都没有“;”或者其他特别符号。

eg:

@SuppressWarnings("deprecation") 	//编译器警告过时(source阶段)
@Deprecated							//过时(Runtime阶段)
@Override								//重写(source阶段)
@Retention(RetentionPolicy.RUNTIME)
//保留注解到程序运行时。(Runtime阶段)
@Target({ElementType.METHOD,ElementType.TYPE})
//标记既能定义在方法上,又能定义在类、接口、枚举上等。
Note

1)添加注解需要有注解类。RetentionPolicy一个枚举类(有三个成员)。

2)Target中可以存放数组。的默认值为任何元素。

ElementType.METHOD:表示只能标记在方法上。

ElementType.TYPE:表示只能标记定义在类上、接口上、枚举上等。

3)ElementType也是枚举类。成员包括:ANNOTATION_TYPE(注解)、CONSTRUCTOR(构造方法)、FIEID(成员变量)、LOCAL_VARIABLE(变量)、METHOD(方法)、PACKAGE(包)、PARAMETER(参数)、TYPE。

4.注解应用结构图:

5.简单相关知识了解:

元注解:注解的注解(理解:给一个注解类再加注解)

数据:数据的数据

信息:信息的信息

6.注解分为三个阶段

java源文--> class
--> 
内存中的字节码。

Retention的注解有三种取值:(分别对应注解的三个阶段)

RetentionPolicy.SOURCE

RetentionPolicy.CLASS

RetentionPolicy.RUNTIME

Note:注解的默认阶段是Class。

7.注解的属性类型

原始类型(就是八个基本数据类型)、String类型、Class类型、数组类型、枚举类型、注解类型。

8.为注解增加属性:

value:是一个特殊的属性,若在设置值时只有一个value属性需要设置或者其他属性都采用默认值时
,那么
value=可以省略,直接写所设置的值即可。

eg@SuppressWarnings("deprecation")

为属性指定缺省值(默认值):

egString
value()
default "blue";
//定义在注解类中

 

数组类型的属性:

egint[]
arrayArr() 
default {3,4,5,5};//定义在注解类中

SunAnnotation(arrayArr={3,9,8})
//设置数组值

Note:如果数组属性中只有一个元素时,属性值部分可以省略大括号。

egSunAnnotation(arrayArr=9)

 

枚举类型的属性:

egEnumDemo.TrafficLamp
lamp()

default EnumDemo.TrafficLamp.RED;

//枚举类型属性, 定义在注解类中,这里使用了自定义的枚举类EnumDemo.java并没有给出相关代码,这里只是举个例子

注解类型的属性:

egMetaAnnotation
annotationAttr()

default @MetaAnnotation("lhm");

//定义在一个注解类中,并指定缺省值,

//此属性关联到注解类:MetaAnnotation.java, 

 

@SunAnnotation(annotationAttr=@MetaAnnotation("flx"))

//设置注解属性值

9.注解应用示例:

注:下面只是示例,涉及枚举的类,并没有给出相关代码。)

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

@Retention(RetentionPolicy.RUNTIME)			//元注解:注解的注解。此注解表示使注解保留到运行时。

//Target中可以存放数组。ElementType.METHOD:表示只能标记在方法上。ElementType.TYPE:表示只能标记定义在类上、接口上、枚举上等。
@Target({ElementType.METHOD,ElementType.TYPE})	

public @interface SunAnnotation {
	String color() default "blue"; //表示有一个color属性,以方法的形式。设置默认属性值为蓝色
	String value();
	//是一个特殊的属性,若在设置值时只有一个value属性需要设置 ,那么value可以省略,直接写所设置的值即可。

	//数组属性
	int[] arrayArr() default {3,4,5,5};

	//枚举类型属性,这里使用了自定的枚举类EnumDemo.java
	EnumDemo.TrafficLamp lamp() default EnumDemo.TrafficLamp.RED;

	//注解类型属性,此时关联到注解类:MetaAnnotation.java,并指定缺省值
	MetaAnnotation annotationAttr() default @MetaAnnotation("lhm");

	//Class类属性:设置默认值 ReflectDemo.java	类
	Class annotationClass() default ReflectDemo.class;

}
@SunAnnotation(annotationClass=ReflectDemo2.class,[email protected]("flx"),color="red",value="abc",arrayArr={1,3,9})		//注解:为注解添加属性值
//若在设置值时只有一个value属性需要设置 ,那么value可以省略,直接写所设置的值即可。
public class AnnotationDemo {

	/**
	 * @param args
	 */

	@SunAnnotation("xyz")
	@SuppressWarnings("deprecation")  //注解:告诉编译器或者开发工具……
	//若在设置值时只有一个value属性需要设置 ,那么value可以省略,直接写所设置的值即可。
	//上面"deprecation"即是省略的value后的值。

	public static void main(String[] args)throws Exception {
		System.runFinalizersOnExit(true);//中间带横线的部分,说明该方法已经过时了。

		//检查某注解是否存在,使用反射;并返回该注解
		if(AnnotationDemo.class.isAnnotationPresent(SunAnnotation.class))
		{
			//获取注解
			SunAnnotation annotation=(SunAnnotation)AnnotationDemo.class.getAnnotation(SunAnnotation.class);
			//获取属性值
			System.out.println("属性color值:"+annotation.color());//调用color属性方法
			System.out.println(annotation.value());
			System.out.println(annotation.arrayArr().length);//这里输出的是数组长度,不能直接输出数组的每一个值,调用得到的是数组哈希地址值
			System.out.println(annotation.lamp().nextLamp().name());//调用注解默认灯的nextLamp方法
			annotation.annotationAttr().value();
			//获取类类型注解中的 类名称
			System.out.println(annotation.annotationClass());

		}
	}
	@Deprecated //表示下面的方法过时了
	public static void sayHello()
	{
		System.out.println("hi");
	}

}

二.扩展注解(JDK 8)

对于注解(也被称做元数据),Java 8 主要有两点改进:类型注解和重复注解。

1.类型注解

1)Java 8 的类型注解扩展了注解使用的范围。

在java 8之前,注解只能是在声明的地方所使用,java8开始,注解可以应用在任何地方。

eg:

  • 创建类实例
new@Interned MyObject();

  • 类型映射
myString = (@NonNull String) str;

  • implements 语句中
class UnmodifiableList<T> implements@Readonly List<@Readonly T> { ... }

  • throw exception声明
void monitorTemperature() throws@Critical TemperatureException { ... }

Note:

  • 在Java 8里面,当类型转化甚至分配新对象的时候,都可以在声明变量或者参数的时候使用注解。
  • Java注解可以支持任意类型。
  • 类型注解只是语法而不是语义,并不会影响java的编译时间,加载时间,以及运行时间,也就是说,编译成class文件的时候并不包含类型注解。

2)新增ElementType.TYPE_USE 和ElementType.TYPE_PARAMETER(在Target上)

新增的两个注释的程序元素类型 ElementType.TYPE_USE 和 ElementType.TYPE_PARAMETER用来描述注解的新场合。

ElementType.TYPE_PARAMETER 表示该注解能写在类型变量的声明语句中。

ElementType.TYPE_USE 表示该注解能写在使用类型的任何语句中(eg:声明语句、泛型和强制转换语句中的类型)。

eg:

@Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE})
@interface MyAnnotation {}

3)类型注解的作用

类型注解被用来支持在Java的程序中做强类型检查。配合第三方插件工具Checker Framework(注:此插件so
easy,这里不介绍了),可以在编译的时候检测出runtime error(eg:UnsupportedOperationException;
NumberFormatException;NullPointerException异常等都是runtime error),以提高代码质量。这就是类型注解的作用。

Note:

使用Checker Framework可以找到类型注解出现的地方并检查。

eg:

import checkers.nullness.quals.*;
public class TestDemo{
    void sample() {
        @NonNull Object my = new Object();
    }
}

使用javac编译上面的类:(当然若下载了Checker Framework插件就不需要这么麻烦了)

javac -processor checkers.nullness.NullnessChecker TestDemo.java

上面编译是通过的,但若修改代码:

@NonNull Object my = null;

但若不想使用类型注解检测出来错误,则不需要processor,正常javac
TestDemo.java是可以通过编译的,但是运行时会报
NullPointerException 异常。

为了能在编译期间就自动检查出这类异常,可以通过类型注解结合 Checker Framework 提前排查出来错误异常。

注意java 5,6,7版本是不支持注解@NonNull,但checker
framework 有个向下兼容的解决方案,就是将类型注解@NonNull 用/**/注释起来。

import checkers.nullness.quals.*;
public class TestDemo{
    void sample() {
        /*@NonNull*/ Object my = null;
    }
}

这样javac编译器就会忽略掉注释块,但用checker framework里面的javac编译器同样能够检测出@NonNull错误。

通过 类型注解 + checker framework 可以在编译时就找到runtime error。

2.重复注解

允许在同一声明类型(类,属性,或方法)上多次使用同一个注解。

Java8以前的版本使用注解有一个限制是相同的注解在同一位置只能使用一次,不能使用多次

Java 8 引入了重复注解机制,这样相同的注解可以在同一地方使用多次。重复注解机制本身必须用 @Repeatable 注解。

实际上,重复注解不是一个语言上的改变,只是编译器层面的改动,技术层面仍然是一样的。

eg:

1)自定义一个包装类Hints注解用来放置一组具体的Hint注解

@interface MyHints {
    Hint[] value();
}

@Repeatable(MyHints.class)
@interface Hint {
    String value();
}

使用包装类当容器来存多个注解(旧版本方法)

@MyHints({@Hint("hint1"), @Hint("hint2")})
class Person {}

使用多重注解(新方法)

@Hint("hint1")
@Hint("hint2")
class Person {}

2)

public class RepeatingAnnotations {
    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface Filters {
        Filter[] value();
    }

    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @Repeatable(Filters.class)
    public @interface Filter {
        String value();
    }
    @Filter("filter1")
    @Filter("filter2")
    public interface Filterable {
    }
    public static void main(String[] args) {
        for (Filter filter : Filterable.class.getAnnotationsByType(Filter.class)) {
            System.out.println(filter.value());
        }
    }
}

输出结果:

filter1

filter2

分析:

注释Filter被@Repeatable( Filters.class )注释。Filters 只是一个容器,它持有Filter, 编译器尽力向程序员隐藏它的存在。通过这样的方式,Filterable接口可以被Filter注释两次。

另外,反射的API提供一个新方法getAnnotationsByType() 来返回重复注释的类型(注意Filterable.class.getAnnotation( Filters.class )将会返回编译器注入的Filters实例)。

3)java 8之前也有重复使用注解的解决方案,但可读性不好。

public @interface MyAnnotation {
     String role();
}  

public @interface Annotations {
    MyAnnotation[] value();
}  

public class RepeatAnnotationUseOldVersion {  

    @Annotations({@MyAnnotation(role="Admin"),@MyAnnotation(role="Manager")})
    public void doSomeThing(){
    }
}

Java8的实现方式(由另一个注解来存储重复注解,在使用时候,用存储注解Authorities来扩展重复注解),可读性更强。

@Repeatable(Annotations.class)
public @interface MyAnnotation {
     String role();
}  

public @interface Annotations {
    MyAnnotation[] value();
}  

public class RepeatAnnotationUseOldVersion {
	@MyAnnotation(role="Admin")
    @MyAnnotation(role="Manager")
    public void doSomeThing(){
    }
} 

----------   诺诺学习技术交流博客、期待与您交流!  
 ----------

详情请查看:http://blog.csdn.net/sun_promise 

时间: 2024-10-01 05:55:48

Java 8 新特性:扩展注解(类型注解和重复注解) ——诺诺"涂鸦"记忆的相关文章

Java 8 新特性:Java 类库的新特性之日期时间API (Date/Time API ) ——诺诺&quot;涂鸦&quot;记忆

----------   诺诺学习技术交流博客.期待与您交流!    ---------- 详情请查看:http://blog.csdn.net/sun_promise  日期时间API (Date/Time API ) 1.Java8之前java.util.Date和Calendar类的弊端 1)最开始的时候,Date既要承载日期信息,又要做日期之间的转换,还要做不同日期格式的显示,职责较繁杂(不遵守单一职责). 后来从JDK 1.1 开始,这三项职责分开了: 使用Calendar类实现日期和

Java 8新特性

现在,是时候把所有Java8的重要特性收集整理成一篇单独的文章了,希望这篇文章能给你带来阅读上的乐趣.开始吧! 目录结构 介绍 Java语言的新特性 2.1 Lambdas表达式与Functional接口 2.2 接口的默认与静态方法 2.3 方法引用 2.4 重复注解 2.5 更好的类型推测机制 2.6 扩展注解的支持 Java编译器的新特性 3.1 参数名字 Java 类库的新特性 4.1 Optional 4.2 Streams 4.3 Date/Time API (JSR 310) 4.

Java 8新特性终极指南

目录结构 介绍 Java语言的新特性 2.1 Lambdas表达式与Functional接口 2.2 接口的默认与静态方法 2.3 方法引用 2.4 重复注解 2.5 更好的类型推测机制 2.6 扩展注解的支持 Java编译器的新特性 3.1 参数名字 Java 类库的新特性 4.1 Optional 4.2 Streams 4.3 Date/Time API (JSR 310) 4.4 JavaScript引擎Nashorn 4.5 Base64 4.6 并行(parallel)数组 4.7

Java 8 新特性 – 终极手册整理

1.简介 毫无疑问,Java 8是自Java  5(2004年)发布以来Java语言最大的一次版本升级,Java 8带来了很多的新特性,比如编译器.类库.开发工具和JVM(Java虚拟机).在这篇教程中我们将会学习这些新特性,并通过真实例子演示说明它们适用的场景. 本教程由下面几部分组成,它们分别涉及到Java平台某一特定方面的内容: 语言 编译器 类库 开发工具 运行时(Java虚拟机) 2.Java的新特性 总体来说,Java 8是一个大的版本升级.有人可能会说,Java 8的新特性非常令人

【整理】Java 8新特性总结

闲语: 相比于今年三月份才发布的Java 10 ,发布已久的Java 8 已经算是老版本了(传闻Java 11将于9月25日发布....).然而很多报道表明:Java 9 和JJava10不是 LTS 版本,和过去的 Java 大版本升级不同,它们只有半年左右的开发和维护期.而未来的 Java11,也就是 18.9 LTS,才是 Java 8 之后第一个 LTS 版本(得到 Oracle 等商业公司的长期支持服务).所以Java 8 就成了最新的一次LTS版本升级,这也是为什么Java开发者对J

Java 8 新特性1-函数式接口

Java 8 新特性1-函数式接口 (原) Lambda表达式基本结构: (param1,param2,param3) -> {代码块} 例1: package com.demo.jdk8; import java.util.Arrays; import java.util.List; import java.util.function.Consumer; public class Test2 { public static void main(String[] args) { for_test

JAVA 8 新特性 (值得学习)

JAVA 8 已经出现好长时间了,大的互联网公司很多都已经使用了,甚至很多知名互联网公司踩过很多坑,也有一些大牛分享出了他们的实战经验.去很多知名的互联网公司经常会被面试官问,你了解java 8吗?你知道它的一些新特性吗?好像似乎成了一面面试官必问的一道题目.这篇博文,只是简答的介绍了一下新特性,同学们还得自己实际操作,深入了解,最好能实际应用到项目里,如果你是项目组里用的比较早,用的比较多的同学,还会被其他的同事注意到你,哈哈. Lambda表达式和函数式接口 下面就是简单的lambda表示的

Java 8新特性前瞻

快端午小长假了,要上线的项目差不多完结了,终于有时间可以坐下来写篇博客了. 这是篇对我看到的java 8新特性的一些总结,也是自己学习过程的总结. 几乎可以说java 8是目前为止,自2004年java 5发布以来的java世界中最大的事件了.它带来了java语言层面上的诸多改变,主要包括下面一些方面:语法.编译器.库.工具和运行时. 一,语法层面: 1,Lambda表达式. lambda表达式是一种可调用对象,它允许我们将函数作为函数参数传入.诸如C++.Groovy.Scala都已经支持la

Spring 4支持的Java 8新特性一览

有众多新特性和函数库的Java 8发布之后,Spring 4.x已经支持其中的大部分.有些Java 8的新特性对Spring无影响,可以直接使用,但另有些新特性需要Spring的支持.本文将带您浏览Spring 4.0和4.1已经支持的Java 8新特性. Spring 4支持Java 6.7和8 Java 8编译器编译过的代码生成的.class文件需要在Java 8或以上的Java虚拟机上运行.由于Spring对反射机制和ASM.CGLIB等字节码操作函数库的重度使用,必须确保这些函数库能理解