• Annotation 注解


    (一)什么是Annotation 

      Annotation,其实是代码里的特殊标记,这些标记可以在编译、类加载、运行时被读取,并执行相应的处理。通过使用注解,开发人员可以在不改变原有逻辑的情况下,在源文件中嵌入一些补充的信息。代码分析工具、开发工具和部署工具可以通过这些补充信息进行验证或者进行部署。

    Annotation提供了一种为程序元素设置元数据的方法,从某些方面来看,Annotation就像修饰符一样,可用于修饰包、类、构造器、方法、成员变量、参数、局部变量的声明,这些信息被存储在Annotation的“name=value"对中。

    Annotation是一个接口,程序可以通过反射来获取指定程序元素的Annotation对象,然后通过Annotation对象来取得注解里的元数据。如果希望让程序中的Annotation在运行时起一定的作用,只有通过某种配套的工具对Annotation中的信息进行访问和处理,访问和处理Annotation的工具统称APT(Annotation Processing Tool).

    (二) Annotation 作用

    1. 标记,用于告诉编译器一些信息

    2. 编译时动态处理,如动态生成代码

    3. 运行时动态处理,如得到注解信息

    (三)Annotation 例子

      

    va7新增的,@FunctionalInterface是Java8新增的。这5个基本的Annotation都定义在java.lang包下。

    1.限定重写父类方法:@Override

    @Override就是用来指定方法重写的,它可以强制一个子类必须复写父类的方法。

    ?

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    public class Fruit

    {

        public void info()

        {

            System.out.println("水果的info方法...");

        }

    }

    class Apple extends Fruit

    {

        // 使用@Override指定下面方法必须重写父类方法

        @Override

        public void inf0()

        {

            System.out.println("苹果重写水果的info方法...");

        }

    }

    PS:@Override主要帮助程序员避免一些低级错误,例如把上面Apple类中的info方法不小心写成了inf0,这样的"低级错误",可能会成为后期排错时的巨大障碍。

    2.标示已过时:@Deprecated

    @Deprecated用于表示某个程序元素(类、方法等)已过时,当其他程序使用已过时的类、方法是,编译器将会给出警告。

    ?

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    class Apple

    {

        // 定义info方法已过时

        @Deprecated

        public void info()

        {

            System.out.println("Apple的info方法");

        }

    }

    public class DeprecatedTest

    {

        public static void main(String[] args)

        {

            // 下面使用info方法时将会被编译器警告

            new Apple().info();

        }

    }

    3.抑制编译器警告:@SuppressWarnings

    @SuppressWarnings指示被该Annotation修饰的程序元素(以及该程序元素中的所有子元素)取消显示指定的编译器警告。

    ?

    1

    2

    3

    4

    5

    6

    7

    8

    9

    // 关闭整个类里的编译器警告

    @SuppressWarnings(value="unchecked")

    public class SuppressWarningsTest

    {

        public static void main(String[] args)

        {

            List<string> myList = new ArrayList();     // ①

        }

    }</string>

    4.Java7的“堆污染”警告与@SafeVarargs

    ?

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    public class Demo {

        public static void main(String[] args){

            List list = new ArrayList<integer>();

            list.add(20);//添加元素时引发unchecked异常

            //下面代码引起"未经检查的转换"的警告,编译、运行时完全正常

            List<string> ls = list;//①

            //但只要访问ls里的元素,如下面代码就会引起运行时异常

            System.out.println(ls.get(0));

        }

    }

    </string></integer>

    Java把引发这种错误的原因称为"堆污染"(Heap pollution),当把一个不带泛型的对象赋给一个带泛型的变量时候,往往会发生这种"堆污染",如上①号粗体字代码所示。

    对于形参个数可变的方法,该形参的类型又是泛型,这将更容易导致"堆污染".例如下面工具类:

    ?

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    public class ErrorUtils

    {

        @SafeVarargs

        public static void faultyMethod(List<string>... listStrArray)

        {

            // Java语言不允许创建泛型数组,因此listArray只能被当成List[]处理

            // 此时相当于把List<string>赋给了List,已经发生了“擦除”

            List[] listArray = listStrArray;

            List<integer> myList = new ArrayList<integer>();

            myList.add(new Random().nextInt(100));

            // 把listArray的第一个元素赋为myList

            listArray[0] = myList;

            String s = listStrArray[0].get(0);

        }

    }</integer></integer></string></string>

    上面程序中的粗体字代码已经发生了"堆污染"。由于该方法有一个形参是List...类型,个数可变的形参相当于数组,但Java又不支持泛型数组,因此程序中只能把List...当成List[]处理,这里就发生了"堆污染"。

    在Java6以及更早的版本中,Java编译器认为faultyMethod()方法完全没有问题,既不会提示错误,也没有提示警告。

    ?

    1

    2

    3

    4

    5

    6

    7

    public class ErrorUtilsTest

    {

        public static void main(String[] args)

        {

            ErrorUtils.faultyMethod(Arrays.asList("Hello!"), Arrays.asList("World!"));

        }

    }

    编译该程序将会在①号代码处引发一个unchecked警告。这个unchecked警告出现得比较"突兀":定义faultyMethod()方法时没有任何警告,调用该方法时却引发了一个"警告".

    从Java7开始,Java编译器将会进行更严格的检查,Java编译器在编译ErrorUtils时就会发出一个警告。

    由此可见,Java7会在定义该方法时就发出"堆污染"警告,这样保证开发者"更早"地注意到程序中可能存在的"漏洞"。但在有些时候,开发者不希望看到这个警告,则可以使用如下三种方式来"抑制"这个警告。

    ①:使用@SafeVarargs修饰引发该警告的方法或构造器

    ②:使用@SuppressWarnings("unchecked")修饰

    ③:编译时使用-Xlint:varargs选项

    5.Java8的函数式接口与@FunctionalInterface

    如果接口中只有一个抽象方法(可以包含多个默认方法或多个static方法),该接口就是函数式接口。函数式接口就是为Java8的Lambda表达式准备的,Java8允许使用Lambda表达式创建函数式接口的实例,因此Java8专门增加了@FunctionalInterface.

    ?

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    @FunctionalInterface

    public interface FunInterface

    {

        static void foo()

        {

            System.out.println("foo类方法");

        }

        default void bar()

        {

            System.out.println("bar默认方法");

        }

        void test(); // 只定义一个抽象方法

    }

    PS:@FunctionalInterface只是告诉编译器检查这个接口,保证该接口只能包含一个抽象方法,否则就会编译出错。@FunctionalInterface只能修饰接口,不能修饰其他程序元素。

     转自 https://www.2cto.com/kf/201803/733649.html

  • 相关阅读:
    React方法论
    React学习记录
    LeetCode 530. Minimum Absolute Difference in BST
    LeetCode 521. Longest Uncommon Subsequence I
    LeetCode 520. Detect Capital
    LeetCode 516. Longest Palindromic Subsequence
    LeetCode 513. Find Bottom Left Tree Value
    LeetCode 506. Relative Ranks
    LeetCode 504. Base 7
    LeetCode 500. Keyboard Row
  • 原文地址:https://www.cnblogs.com/cducz/p/10546192.html
Copyright © 2020-2023  润新知