欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

谈谈注解那些事

程序员文章站 2022-05-05 17:38:50
...

1.注解定义
在我看来哈,注解其实就是简化我们程序,提高和优化我们程序的存在
主要分成那么几种:
根据注解参数的个数,可以将注解分为三类:
    1.标记注解:一个没有成员定义的Annotation类型被称为标记注解。这种Annotation类型仅使用自身的存在与否来为我们提供信息。比如后面的系统注解@Override;
    2.单值注解
    3.完整注解 
  根据注解使用方法和用途,我们可以将Annotation分为三类:
    1.JDK内置系统注解
    2.元注解
    3.自定义注解
上面几个分类我就弄弄jdk自带的内置注解和自定义的注解,剩下的那个一般有api说明,往底层哇,也就那样
基础注解也就是jdk的内置系统注解
首先说一下最下面那层元注解
这个就是jdk自定义,限制注解可以标注的范围啦,生命周期之类的

@Target({ElementType.CONSTRUCTOR,ElementType.FIELD,ElementType.METHOD})
// Target 注解的作用域   CONSTRUCTOR 构造方法声明,FIELD 字段声明,LOCAL_VARIABLE 局部变量声明 ,METHOD 方法声明,PACKAGE 包声明,PARAMETER 参数声明,TYPE 类接口。
@Retention(RetentionPolicy.RUNTIME)
//Retention 生命周期 SOURCE 只在源码显示,编译时会丢弃,CLASS 编译时会记录到class中,运行时忽略,RUNTIME 运行时存在,可以通过反射读取。
@Inherited 
//Inherited 允许子类继承
@Documented 
//Documented 生成javadoc的时候包含注解

然后就是jdk自带的几个注解
主要就介绍3个
1Override限定父类重写方法
2Deprecated:用于表示某个程序元素(方法或类)已过时
3.SuppressWarnings:抑制编程器警告

  • @Override
    是一个标记注解类型,它被用作标注方法。它说明了被标注的方法重载了父类的方法,起到了断言的作用。如果我们使用了这种Annotation在一个没有覆盖父类方法的方法时,java编译器将以一个编译错误来警示。这个annotaton常常在我们试图覆盖父类方法而确又写错了方法名时发挥威力。使用方法极其简单:在使用此annotation时只要在被修饰的方法前面加上@Override即可。下面的代码是一个使用@Override修饰一个企图重载父类的displayName()方法,而又存在拼写错误的实例:
   public class Fruit {

    public void displayName(){
        System.out.println("水果的名字是:*****");
    }
}

class Orange extends Fruit {
    @Override
    public void displayName(){
        System.out.println("水果的名字是:桔子");
    }
}

class Apple extends Fruit {
    @Override
    public void displayname(){
        System.out.println("水果的名字是:苹果");
    }
}

Orange 类编译不会有任何问题,Apple 类在编译的时候会提示相应的错误。@Override注解只能用于方法,不能用于其他程序元素。然后总结一下其实,就是判断已下当前方法是不是已经继承类的子类


  • @Deprecated,标记已过时:


    样Deprecated也是一个标记注解。当一个类型或者类型成员使用@Deprecated修饰的话,编译器将不鼓励使用这个被标注的程序元素。而且这种修饰具有一定的
    “延续性”:如果我们在代码中通过继承或者覆盖的方式使用了这个过时的类型或者成员,虽然继承或者覆盖后的类型或者成员并不是被声明为
    @Deprecated,但编译器仍然要报警。

    值得注意,@Deprecated这个annotation类型和javadoc中的
    @deprecated这个tag是有区别的:前者是java编译器识别的,而后者是被javadoc工具所识别用来生成文档(包含程序成员为什么已经过
    时、它应当如何被禁止或者替代的描述)。

    在java5.0,java编译器仍然象其从前版本那样寻找@deprecated这个javadoc
    tag,并使用它们产生警告信息。但是这种状况将在后续版本中改变,我们应在现在就开始使用@Deprecated来修饰过时的方法而不是
    @deprecated javadoc tag。

    下面一段程序中使用了@Deprecated注解标示方法过期,同时在方法注释中用@deprecated tag
    标示该方法已经过时,代码如下:

 class AppleService {
    public void displayName(){
        System.out.println("水果的名字是:苹果");
    }
    
    /**
     * @deprecated 该方法已经过期,不推荐使用
     */
    @Deprecated
    public void showTaste(){
        System.out.println("水果的苹果的口感是:脆甜");
    }
    
    public void showTaste(int typeId){
        if(typeId==1){
            System.out.println("水果的苹果的口感是:酸涩");
        }
        else if(typeId==2){
            System.out.println("水果的苹果的口感是:绵甜");
        }
        else{
            System.out.println("水果的苹果的口感是:脆甜");
        }
    }
}

public class FruitRun {

    /**
     * @param args
     */
    public static void main(String[] args) {
        Apple apple=new Apple();
        apple.displayName();    
        
        AppleService appleService=new AppleService();
        appleService.showTaste();
        appleService.showTaste(0);
        appleService.showTaste(2);
    }

}

AppleService类的showTaste() 方法被@Deprecated标注为过时方法,在FruitRun类中使用的时候,编译器会给出该方法已过期,不推荐使用的提示。
 -----------------------------------------------------------
SuppressWarnnings,抑制编译器警告:

  • @SuppressWarnings
    被用于有选择的关闭编译器对类、方法、成员变量、变量初始化的警告。在java5.0,sun提供的javac编译器为我们提供了-Xlint选项来使编译器对合法的程序代码提出警告,此种警告从某种程度上代表了程序错误。例如当我们使用一个generic
    collection类而又没有提供它的类型时,编译器将提示出"unchecked
    warning"的警告。通常当这种情况发生时,我们就需要查找引起警告的代码。如果它真的表示错误,我们就需要纠正它。例如如果警告信息表明我们代码中的switch语句没有覆盖所有可能的case,那么我们就应增加一个默认的case来避免这种警告。
      有时我们无法避免这种警告,例如,我们使用必须和非generic的旧代码交互的generic
    collection类时,我们不能避免这个unchecked
    warning。此时@SuppressWarning就要派上用场了,在调用的方法前增加@SuppressWarnings修饰,告诉编译器停止对此方法的警告。
      SuppressWarning不是一个标记注解。它有一个类型为String[]的成员,这个成员的值为被禁止的警告名。对于javac编译器来讲,被-Xlint选项有效的警告
    名也同样对@SuppressWarings有效,同时编译器忽略掉无法识别的警告名。
      annotation语法允许在annotation名后跟括号,括号中是使用逗号分割的name=value对用于为annotation的成员赋值。实例如下:
public class FruitService {
    
    @SuppressWarnings(value={ "rawtypes", "unchecked" })
    public static  List<Fruit> getFruitList(){
        List<Fruit> fruitList=new ArrayList();
        return fruitList;
    }
    
    @SuppressWarnings({ "rawtypes", "unchecked" })
    public static  List<Fruit> getFruit(){
        List<Fruit> fruitList=new ArrayList();
        return fruitList;
    }

    @SuppressWarnings("unused")
    public static void main(String[] args){
        List<String> strList=new ArrayList<String>();
    }
}

在这个例子中SuppressWarnings annotation类型只定义了一个单一的成员,所以只有一个简单的value={…}作为name=value对。又由于成员值是一个数组,故使用大括号来声明数组值。注意:我们可以在下面的情况中缩写annotation:当annotation只有单一成员,并成员命名为"value="。这时可以省去"value="。比如将上面方法getFruit()的SuppressWarnings annotation就是缩写的。

SuppressWarnings注解的常见参数值的简单说明:

1.deprecation:使用了不赞成使用的类或方法时的警告;
    2.unchecked:执行了未检查的转换时的警告,例如当使用集合时没有用泛型 (Generics) 来指定集合保存的类型;
    3.fallthrough:当 Switch 程序块直接通往下一种情况而没有 Break 时的警告;
    4.path:在类路径、源文件路径等中有不存在的路径时的警告;
    5.serial:当在可序列化的类上缺少 serialVersionUID 定义时的警告;
    6.finally:任何 finally 子句不能正常完成时的警告;
    7.all:关于以上所有情况的警告。
    
   --------------------------------------------------------------------------------------------
   反正以上几个感觉没啥大用,多用在细节

自定义注解
感觉这个东西挺有用,上来先自定义一个,注解

package com.wxx.interfacep;

public @interface MyAnn {
     public String defalt();
}

这就是一个注解了,然而感觉并没有什么用,还傻傻的放到属性上面,以为会自动的传值,这个自定义注解的和反射配合才能实现它的逻辑功能,懒得写,自己上网查了一个,测试一下行就可以,就当是个记录了
首先定义几个注解,注解一般分default和public,一个值一般直接属性带小括号

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface FruitColor {
    /**
     * 颜色枚举
     * @author peida
     *
     */
    public enum Color{ BULE,RED,GREEN};
    
    /**
     * 颜色属性
     * @return
     */
    Color fruitColor() default Color.GREEN;

}
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface FruitName {
    String value() default "";
}
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface FruitProvider {
		     /**
		      * 供应商编号
		      * @return
		      */
		     public int id() default -1;  
		    /**
		      * 供应商名称
		      * @return
		      */
	         public String name() default "";
		     /**
		      * 供应商地址
		      * @return
		      */
	         public String address() default "";
}

然后把注解放到属性上:

public class Apple {
    
    @FruitName("Apple")
    private String appleName;
    
    @FruitColor(fruitColor=Color.RED)
    private String appleColor;
    
    @FruitProvider(id=1,name="陕西红富士集团",address="陕西省西安市延安路89号红富士大厦")
    private String appleProvider;
    
    public void setAppleColor(String appleColor) {
        this.appleColor = appleColor;
    }
    public String getAppleColor() {
        return appleColor;
    }
    
    public void setAppleName(String appleName) {
        this.appleName = appleName;
    }
    public String getAppleName() {
        return appleName;
    }
    
    public void setAppleProvider(String appleProvider) {
        this.appleProvider = appleProvider;
    }
    public String getAppleProvider() {
        return appleProvider;
    }
    
    public void displayName(){
        System.out.println("水果的名字是:苹果");
    }
}

剩下就是最灵魂的东西,使用反射实现逻辑代码

public class FruitInfoUtil {
	 public static void getFruitInfo(Class<?> clazz){
	        
	        String strFruitName=" 水果名称:";
	        String strFruitColor=" 水果颜色:";
	        String strFruitProvicer="";
	        
	        Field[] fields = clazz.getDeclaredFields();
	        for(Field field :fields) {

               if(field.isAnnotationPresent(FruitName.class)){
	                FruitName fruitName = (FruitName) field.getAnnotation(FruitName.class);
	                strFruitName=strFruitName+fruitName.value();
	                System.out.println(strFruitName);
	            }
	            else if(field.isAnnotationPresent(FruitColor.class)){
	                FruitColor fruitColor= (FruitColor) field.getAnnotation(FruitColor.class);
	                strFruitColor=strFruitColor+fruitColor.fruitColor().toString();
	                System.out.println(strFruitColor);
	            }
	            else if(field.isAnnotationPresent(FruitProvider.class)){
	                FruitProvider fruitProvider= (FruitProvider) field.getAnnotation(FruitProvider.class);
	                strFruitProvicer=" 供应商编号:"+fruitProvider.id()+" 供应商名称:"+fruitProvider.name()+" 供应商地址:"+fruitProvider.address();
	                System.out.println(strFruitProvicer);
	            }
	        }
	    }
}

最后调用一下就可以了

public class ZhuJie {
	
 @Test
 public void testAnno() {
	  FruitInfoUtil.getFruitInfo(Apple.class);
 }
}

输出结果

 水果名称:Apple
 水果颜色:RED
 供应商编号:1 供应商名称:陕西红富士集团 供应商地址:陕西省西安市延安路89号红富士大厦
相关标签: java深入了解