📜  Java注释类型

📅  最后修改于: 2020-09-26 13:30:28             🧑  作者: Mango

在本教程中,我们将借助示例学习不同类型的Java批注。

Java批注是我们程序源代码的元数据(有关数据的数据)。 Java SE提供了几个预定义的注释。此外,我们还可以根据需要创建自定义注释。

如果您不知道什么是注释,请访问Java注释教程。

这些注释可以分类为:

1. 预定义的注释

  • @Deprecated
  • @Override
  • @SuppressWarnings
  • @SafeVarargs
  • @FunctionalInterface

2. 自定义注释

3. 元注释

  • @Retention
  • @Documented
  • @Target
  • @Inherited
  • @Repeatable

预定义的注释类型

1. @已弃用

@Deprecated批注是一个标记批注,它指示不赞成使用的元素(类,方法,字段等),并已由较新的元素替换。

其语法为:

@Deprecated
accessModifier returnType deprecatedMethodName() { ... }

当程序使用已声明为已弃用的元素时,编译器将生成警告。

我们使用Javadoc @deprecated标记来记录已弃用的元素。

/**
 * @deprecated
 * why it was deprecated
 */
@Deprecated
accessModifier returnType deprecatedMethodName() { ... }

示例1:@Deprecated注释示例

class Main {
  /**
   * @deprecated
   * This method is deprecated and has been replaced by newMethod()
   */
  @Deprecated
  public static void deprecatedMethod() { 
    System.out.println("Deprecated method"); 
  } 

  public static void main(String args[]) {
    deprecatedMethod();
  }
}

输出

Deprecated method

2. @Override

@Override批注指定子类的方法使用相同的方法名称,返回类型和参数列表覆盖超类的方法。

重写方法时,并非必须使用@Override 。但是,如果使用它,则在覆盖方法时,如果出现错误(例如错误的参数类型),则编译器将给出错误。

示例2:@Override注释示例

class Animal {

  // overridden method
  public void display(){
    System.out.println("I am an animal");
  }
}

class Dog extends Animal {

  // overriding method
  @Override
  public void display(){
    System.out.println("I am a dog");
  }

  public void printMessage(){
    display();
  }
}

class Main {
  public static void main(String[] args) {
    Dog dog1 = new Dog();
    dog1.printMessage();
  }
}

输出

I am a dog

在此示例中,通过使对象Dog1Dog类,我们可以调用其方法printMessage() ,然后执行display()语句。

由于在两个类中都定义了display() ,所以Dog子类的方法将覆盖Animal的超类方法。因此,将调用子类的display()


3. @SuppressWarnings

顾名思义, @SuppressWarnings批注指示编译器禁止在程序执行时生成警告。

我们可以指定要禁止的警告类型。可以禁止的警告是特定于编译器的,但警告分为两类: 弃用未检查

为了禁止显示特定类别的警告,我们使用:

@SuppressWarnings("warningCategory")

例如,

@SuppressWarnings("deprecated")

为了禁止显示多种警告,我们使用:

@SuppressWarnings({"warningCategory1", "warningCategory2"})

例如,

@SuppressWarnings({"deprecated", "unchecked"})

deprecated类别将指示编译器在使用不推荐使用的元素时禁止显示警告。

unchecked类别会指示编译器在使用原始类型时禁止显示警告。

并且,未定义的警告将被忽略。例如,

@SuppressWarnings("someundefinedwarning")

示例3:@SuppressWarnings注释示例

class Main {
  @Deprecated
  public static void deprecatedMethod() { 
    System.out.println("Deprecated method"); 
  } 
  
  @SuppressWarnings("deprecated")
  public static void main(String args[]) {
    Main depObj = new Main();
    depObj. deprecatedMethod();
  }
}

输出

Deprecated method

在这里, deprecatedMethod()已被标记为已弃用,并且在使用时会给出编译器警告。通过使用@SuppressWarnings("deprecated")批注,我们可以避免编译器警告。


4. @SafeVarargs

@SafeVarargs批注断言,带注释的方法或构造函数不会对其varargs(可变数量的参数)执行不安全的操作。

我们只能在无法覆盖的方法或构造函数上使用此注释。这是因为覆盖它们的方法可能会执行不安全的操作。

在Java 9之前,我们只能在final或static方法上使用此注释,因为它们不能被覆盖。现在,我们也可以将此注释用于私有方法。

示例4:@SafeVarargs注释示例

import java.util.*;

class Main {

  private void displayList(List... lists) {
    for (List list : lists) {
      System.out.println(list);
    }
  }

  public static void main(String args[]) {
    Main obj = new Main();

    List universityList = Arrays.asList("Tribhuvan University", "Kathmandu University");
    obj.displayList(universityList);

    List programmingLanguages = Arrays.asList("Java", "C");
    obj.displayList(universityList, programmingLanguages);
  }
}

警告事项

Type safety: Potential heap pollution via varargs parameter lists
Type safety: A generic array of List is created for a varargs 
 parameter

输出

Note: Main.java uses unchecked or unsafe operations.
[Tribhuvan University, Kathmandu University]
[Tribhuvan University, Kathmandu University]
[Java, C]

在这里, List ... lists指定List类型的变长参数 。这意味着方法displayList()可以具有零个或多个参数。

上面的程序编译没有错误,但是当不使用@SafeVarargs批注时会发出警告。

当在上面的示例中使用@SafeVarargs批注时,

@SafeVarargs
 private void displayList(List... lists) { ... }

我们得到相同的输出,但没有任何警告。当使用此批注时,未经检查的警告也会被删除。


5. @FunctionalInterface

Java 8首先引入了此@FunctionalInterface批注。此注释指示使用它的类型声明是一个功能接口。一个功能接口只能有一个抽象方法。

示例5:@FunctionalInterface注释示例

@FunctionalInterface
public interface MyFuncInterface{
  public void firstMethod(); // this is an abstract method
}

如果我们添加另一个抽象方法,那么说

@FunctionalInterface
public interface MyFuncInterface{
  public void firstMethod(); // this is an abstract method
  public void secondMethod(); // this throws compile error
}

现在,当我们运行程序时,我们将收到以下警告:

Unexpected @FunctionalInterface annotation
@FunctionalInterface ^ MyFuncInterface is not a functional interface
multiple non-overriding abstract methods found in interface MyFuncInterface

使用@FunctionalInterface注释不是强制性的。编译器会将满足功能接口定义的任何接口视为功能接口。

我们使用此注释来确保功能接口只有一种抽象方法。

但是,它可以具有任意数量的默认方法和静态方法,因为它们具有实现。

@FunctionalInterface
public interface MyFuncInterface{
  public void firstMethod(); // this is an abstract method
  default void secondMethod() { ... } 
  default void thirdMethod() { ... } 
}

自定义注释

也可以创建我们自己的自定义注释。

其语法为:

[Access Specifier] @interface {         
  DataType () [default value];
}

这是您需要了解的有关自定义注释的信息:

  • 可以使用@interface加上注释名称来创建注释。
  • 批注可以具有看起来像方法的元素,但是它们没有实现。
  • 默认值为可选。参数不能为空值。
  • 方法的返回类型可以是原始,枚举, 字符串,类名或这些类型的数组。

示例6:自定义注释示例

@interface MyCustomAnnotation {
  String value() default "default value";
}

class Main {
  @MyCustomAnnotation(value = "programiz")
  public void method1() {
    System.out.println("Test method 1");
  }

  public static void main(String[] args) throws Exception {
    Main obj = new Main();
    obj.method1();
  }
}

输出

Test method 1

元注释

元注释是应用于其他注释的注释。

1. @保留

@Retention注释指定注释可用的级别。

其语法为:

@Retention(RetentionPolicy)

保留策略有3种类型:

  • RetentionPolicy.SOURCE-注释仅在源级别可用,并且被编译器忽略。
  • RetentionPolicy.CLASS-注释在编译时可供编译器使用,但被Java虚拟机(JVM)忽略。
  • RetentionPolicy.RUNTIME-注释可用于JVM。

例如,

@Retention(RetentionPolicy.RUNTIME)
public @interface MyCustomAnnotation{ ... }

2. @记录

默认情况下,自定义注释不包含在官方Java文档中。为了将注释包含在Javadoc文档中,我们使用@Documented注释。

例如,

@Documented
public @interface MyCustomAnnotation{ ... }

3. @Target

我们可以使用@Target注释将注释限制为应用于特定目标。

其语法为:

@Target(ElementType)

ElementType可以具有以下类型之一:

Element Type Target
ElementType.ANNOTATION_TYPE Annotation type
ElementType.CONSTRUCTOR Constructors
ElementType.FIELD Fields
ElementType.LOCAL_VARIABLE Local variables
ElementType.METHOD Methods
ElementType.PACKAGE Package
ElementType.PARAMETER Parameter
ElementType.TYPE Any element of class

例如,

@Target(ElementType.METHOD)
public @interface MyCustomAnnotation{ ... }

在此示例中,我们仅将此注释的使用限制为方法。

注意:如果未定义目标类型,则注释可用于任何元素。


4. @继承

默认情况下,注释类型不能从超类继承。但是,如果我们需要将注释从超类继承到子类,则可以使用@Inherited注释。

其语法为:

@Inherited

例如,

@Inherited
public @interface MyCustomAnnotation { ... }

@MyCustomAnnotation
public class ParentClass{ ... }

public class ChildClass extends ParentClass { ... }

5. @可重复

@Repeatable标记的@Repeatable可以多次应用于同一声明。

@Repeatable(Universities.class)
public @interface University {
  String name();
}

@Repeatable批注中定义的值是容器批注。容器注释具有上述可重复注释的数组类型的变量 。在这里, Universities是包含的注释类型。

public @interface Universities {
  University[] value();
}

现在, @University批注可以在同一声明上多次使用。

@University(name = "TU")
@University(name = "KU")
private String uniName;

如果需要检索注释数据,则可以使用Reflection API。

要检索注释值,我们使用在反射API中定义的getAnnotationsByType()getAnnotations()方法。