面试必问系列之----Java中的注解(Annotation)详解(一)

182 阅读5分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第五天,点击查看活动详情 

注解(Annotation)

概括

注解就是JDK5开始增加的注释机制,注解是代码里的特殊标记,这些标记可以在编译、类加载、运行时被读取、并执行相应的处理。通过使用注解,开发人员可以在不改变原有原有逻辑的情况下,在源文件中嵌入一些补充的信息。

注解分类

注解分为标准注解(内置注解)和元注解
注意标准注解也可以叫内置注解,本文就以标准注解来概括

  1. 标准注解
    标准注解就是Java自带的注解,包括@Override、@Deprecated、@SuppressWarnings和@SafeVarargss
  • @Override
    对覆盖超类中的方法进行标记,如果被标记的方法并没有实际覆盖超类中的方法,则编译器会发出警告
  • @Deprecated
    对不鼓励使用或者已经过时的方法添加注解,当编程人员使用这些方法时,将会在编译时显示提示信息
  • @SuppressWarnings
    选择性的取消特定代码段中的警告
  • @SafeVarargss
    JDK7中新增,用来申明使用了可变长度参数的方法,其在与泛型类型一起使用时不会出现类型安全问题

@Override

@Override修饰一个方法不是当前类首先声明的,而是在某个父类或实现的接口中声明的,当前类“重写”了该方法需要使用该注解,比如:

static class Base{
  public void doSome(){

  }
}

static class Child extends Base{
  @Override
  public void doSome(){
    System.out.println("doSome");
  }
}

解析: Child继承了Base,并重了Base类中的doSome()方法,重写方法我需要添加@Override注解,但是你会发现我发现,我们在重写的时候的不添加@Override注解IDE也不会报错,代码逻辑也不会有所改变,那为什么我需要在重写的时候需要添加该注解呢?

那是因为我们添加该注解时可以帮助我们减少一个一些编程错误。如果方法添加了@Override注解,但是没有任何父类或借口都不没有声明该方法,则编译器会报错,强制程序员修改改错误。我们就以上面的的列子为例,如果BasedoSome()方法被修改,如下:

static class Base{
  public void noDoSome(){

  }
}

但是程序员在Child中却忘记修改了,如果没有没有@Override注解的话,IDE就不会报任何错误,IDE会默认为dosome()Child新加的方法,这就与程序员期望的不符了

所以,如果方法是父类或接口中定义的,加上@Override会让IDE帮你减少出错

@Deprecated

@Deprecated可以修饰的范围很广,包括类、方法、字段、参数等,它表示对应的代码已经过时了,程序员不该继续使用它,不过这只是一种警告,而不是强制性,如果你非要使用也不是不可以,但是在IDE中,会给Deprecated元素加上一条删除线表示警告。
比如,在Data中就有很多过时的方法:

@Deprecated
public Data(int year,int manth,int data)

@Deprecated
public int getYear()

当然,我们在声明元素为@Deprecated时,我们也应该用Java文档注释的方式告诉替代方案,就是JDk9开始,@Deprecated多了两个属性:sinceforRemoval

  • since
    是一个字符串,表示是从哪一个版本开始过时
  • forRemoval
    forRemoval是一个boolean值,表示将来会删除

接下来我们来看一下例子:

@Deprecated(since = "9")
public Integer(int value){

}

@SuppressWarnings

@SuppressWarnings表示压制Java的变异警告,它有一个必填参数,表示压制哪种类型的警告,它也可以修饰大部分代码元素,在更大范围的修饰也会对内部元素起效,比如,在类上的注解会影响到方法,在方法上的注解会影响代码行
我们还是以Date方法的效用,我们可以这样压制警告

@SuppressWarnings({"deprecation",unused})
public static void main(String[] args){
  Date date = new Date(2017,4,12)
  int year = date.getYear()
}

那么@SuppressWarnings可以忽略哪些警告呢?具体如下:

关键字详解
all抑制所有警告
boxing抑制装箱、拆箱操作时候的警告
cast抑制映射相关的警告
dep-ann抑制启用注释的警告
deprecation抑制过期方法警告
fallthrough抑制确在switch中缺失breaks的警告
finally抑制finally模块没有返回的警告
hiding隐藏是为了抑制相对于隐藏变量的局部变量的警告
incomplete-switch忽略没有完整的switch语句
nls忽略非nls格式的字符
null忽略对null的操作
rawtypes使用泛型类参数时忽略没有指定相应的类型
restriction限制抑制与使用劝阻或禁止引用相关的警告
serial忽略在序列化类中没有声明serialVersionUID变量
static-access抑制不正确的静态访问方式警告
synthetic-access抑制子类没有按最优方法访问内部类的警告
unchecked抑制没有进行类型检查操作的警告
unqualified-field-access抑制没有进行类型检查操作的警告
unused抑制没被使用过的代码的警告

@SafeVarargss

在声明具有模糊类型(比如:泛型)的可变参数的构造函数或方法时,Java编译器会报unchecked警告。鉴于这些情况,如果程序员断定声明的构造函数和方法的主体不会对其varargs参数执行潜在的不安全的操作,可使用@SafeVarargs进行标记,这样的话,Java编译器就不会报unchecked警告。

public class SafeVarargs { 
    // 这其实不是一个安全的类型检查 
    @SafeVarargs static void m(List<String>...lists){
        // 先会存储到 array[0] 的位置 
        Object[] array = lists; 
        List<Integer> tmpList = Arrays.asList(42); 
        // array[0] 又保存了tmpList(Integer)进行覆盖 
        // tmpList是一个List对象(类型已经擦除),赋值给Object类型的对象是允许的(向上转型),
        // 能够编译通过 array[0] = tmpList; 
        // 实际取出来的应该是 42 
        String s = lists[0].get(0); 
    } 
    
    public static void main(String[] args) { 
    List<String> list1 = Arrays.asList("one","two"); 
    m(list1); 
    } 
}

总结:

Java中常用的标准注解大致就这些,元注解和自定义注解我们将会在下一篇来详细说明