java的注解

@是java的注解

即annotation
1. 可以理解为插件,是代码级别的插件,在类的方法上写:@xxx,就是在代码上插入一个插件
2. java注解是附加在代码中的一些元信息,用于一些工具在编译、运行时进行解析和使用,起到说明、配置的功能。注解不会影响代码的实际逻辑,仅仅起到辅助性作用

3. 要先学习java的反射机制,然后再来理解java注解

J2SE5.0版本在java.long.annotation提供了四种元注解,专门注解其他的注解:
@Documented-是否生成javadoc文档
@Retention-什么时候使用该注解
@Target-用于表面注解使用范围
@Inherited-用于表面注解可继承
注解如同标签
想象代码具有生命,注解就是对于代码中某些鲜活个体贴上去一张标签。简化来讲,注解如同一张标签。
注解同clsss和interface一样,也属于一种类型。他是在java SE5.0版本中开始引入的概念
@Retention:定义注解的保留策略
@Retention(RetentionPolicy.SOURCE)//注解仅存在于源码中,在clss字节码文件中不包含
@Retention(RetentionPolicy.Class)//默认的保留策略,注解会在class字节码文件中存在,单运行时无法获得

@Retention(RetentionPolicy.RUNTIME) //注解会在class字节码文件中存在,运行时可以通过反射取到

注解的定义
注解通过@interface关键字进行定义
public @interface TestAnnotation{
}
他的形式跟接口类似,不过前面多了一个@符合。上面的代码创建了一个名为TestAnnotation的注解。你可以简单理解为创建了一张名为TestAnnotation的标签。
注解的应用
@TestAnnotation
public class Test{
}
创建一个Test类,然后在类定义的地方加上@TestAnnotation就可以用TestAnnotation注解这个类了。
你可以理解为将Testnnotation这张标签铁道Test这个类上。
不过要想注解能够正常工作,还需要介绍下一个新的概念,那就是元注解
元注解
元注解是可以主街道注解上的注解,或者说元注解是一种基本注解,但是他能够应用到其他的注解上面。
元注解也是一张标签,一张特殊的标签,他的作用和目的就是给其他普通标签进行解释说明
元标签有@Retention、@Documented、@Target、@Inherited、@Repeatable 5种
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@interface Test{}


@Test
public class A{}
public class B extends A{}
注解Test被@Inherited修饰,之后类A被Test注解,类B继承类A,类B也拥有Test这个注解
@Repeatable
Repeatable自然是可重复的意思,@Repeatable是java 1.8才加进来的,所以算是一个新特性
什么样的注解会多次应用呢,通常是注解的值可以同时取多个
举例,一个人他既是程序员又是产品经理,同时还是画家
@interface Persons{
Person[] value();
}


@Repeatable(Persons.class)
@inerface Person{
String role default “”;
}


@Person(role=”artist”)
@Person(role=”coder”)
@person(role=”PM”)
public class SuperMan{
}
注意上面的代码,@Repeatable注解了Person,而@Repeatable后面括号中的类相当于一个容器注解。
什么是容器注解?就是用来存放其他注解的地方。它本身也是一个注解。
容器注解,按照规定,它里面必须要有一个value的属性,属性类型是一个被@Repeatable注解过的注解数组,注意,他是数组。
注解的属性
注解的属性也叫做成员变量。注解只有成员变量,没有方法。注解的成员变量在注解的定义中以“无形参的方法”形式来声明,其方法名定义了该成员变量的名字,其返回值定义了该成员变量的类型。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @Interface TestAnnotation{
int id();
String msg();
}
上面代码定义了TestAnnotation这个注解中拥有id和msg两个属性。在使用的时候,我们应该给他们进行赋值。
赋值的方法在注解的括号内以value=“”形式,多个属性之前间用,隔开
@TestAnnotation(id=3,msg=”hello annotation”)
public class Test{
}
需要注意的是,在注解中定义属性时他的类型必须是8种基本类型外加类、接口、注解及他们的数组。
注解中属性可以有默认值,默认值需要用default关键值指定。比如
@Target(ElemenType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface TestAnnotation{
public int id() default -1;
public String msg() default “hi”;
}
TestAnnotation 中id属性默认值为-1,msg属性默认值为hi
他可以这样应用
@TestAnnotation()
public class Test{}
因为有默认值,所以无需再在@TestAnnotation后面的括号中进行赋值了,这一步可以省略
另外,还有一种情况,如果一个注解内仅仅只有一个名字为value的属性时,应用这个注解可以直接将属性值填写到括号内
public @interface  Check{
String value();
}
上面代码中,Check这个注解只有一个value熟悉,所以可以这样应用
@Check(“hi”)
int a;
这和下面的效果一样的
@Check(value=”hi”)
int a;
最后,还需要注意的一种情况是一个注解没有任何属性,比如
public @interface Perform{}
那么在应用这个注解的时候,括号都可以省略。
@Perform

public void tesMethod(){}

Java预置的注解
@Deprecated
这个元素用来标记过时的元素。如编译器在编译阶段遇到这个注解时会发出提醒警告,告诉开发者正在调用一个过时的元素,比如过时的方法、过时的类、过时的成员变量。
Public class Hero{
@Deprecated
public void say(){
System.out.println(“Noting has to say!”);
}


public void speak(){
System.out.println(“I hava a dream!”);
}
}
定义了一个Hero类,他有两个方法say()和speak(),其中say()被@Deprecated注解。然后我们在IDE中分别调用他们
Hero hero = new Hero();
hero.say();
hero.speak();
@Override
这个大家都很熟悉,提示子类要复写父类中被@Override修饰的方法
@SuppressWarnings
阻止警告的意思,之前说过被调用被@Deprecated注解的方法之后,编译器会警告提醒,而有时候开发者会忽略这种警告,他们可以在调用的地方通过@SuppressWarnings达到目的
@SafeVarargs
参数安全类型注解。他的目的是提醒开发者不要用参数做一些不安全的操作,他的存在会阻止编译器产生unchecked这样的警告,他在java1.7版本中加入
@SafeVarargs //Not actually safe!
Static void m(List<String>… stringLists){
Object[] array = stringLists;
List<Integer> tmpList = Arrays.asList(42);
Array[0] = tmpList;
String s = stringLists[0].get(0);
}
@FunctionalInterface
函数式接口注解,这个是java1.8版本引入的新特性。函数式编程很火,所以java 8也及时添加了这个特性
函数式接口(Functional Interface)就是一个具有一个方法的普通接口
注解的提取
要想正确检阅注解,离不开一个手段,那就是反射
注解与反射
注解通过反射获取。首先可以通过Class对象的isAnnotationPresent()方法判断他是否应用了某个注解
public Boolean isAnnotationPresent(Class<? extends Annotation> annotationClass){}
然后通过getAnnotation()方法来获取Annotation对象
public <A extends Annotation> A getAnnotation(Class{A> annotationClass}{}
或者getAnnotation()方法
public Annotation[] getAnnotations(){}
前一种方法返回指定类型的注解,后一种方法返回注解这个元素上的所有注解
如果获取到Annotation不为null,则就可以调用他们的属性方法了,比如
1.定义TestAnnotation注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME) 


@interface TestAnnotation {
    public int id() default -1;
    public String msg()  default "Hi";
}
注意:如果没有@Retention(RetentionPolicy.RUNTIME) 就没有运行结果,增加这个注解,说明在整个过程都存在
2.使用注解
@TestAnnotation
public class Test{
public static void main(String[] args){
Boolean hasAnnotation = Test.class.isAnnotationPresent(TestAnnotation.class);
If(hasAnnotation){
TestAnnotation testAnnotation = Test.class.getAnnotation(TestAnnotation.class);
System.out.println(“id:”+testAnnotation.id());
System.out.println(“msg:”+testAnnotation.msg());
}
}
}
程序的运行结果是:
id:-1
msg:
这个正是TestAnnotation中id和msg的默认值
上面的例子,只是检阅出了注解在类上的注解,其实属性、方法上的注解照样是可以的,同样还是要假手于反射
举例:
1)注解Check,只有value这个熟悉
@Retention(RetentionPolicy.RUNTIME)
public @interface Check {
    String value() ;
}
2)定义没有任何属性的注解Perform
@Retention(RetentionPolicy.RUNTIME)
public @interface Perform {
}
3)使用
package java_test;
import com.sun.xml.internal.rngom.ast.builder.Annotations;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;


@TestAnnotation(msg="hello everyone")
public class test {


   @Check(value="hi")
   int a;


   @Perform
   public void testMethod(){}


   @SuppressWarnings("deprecation")
   public void test1(){
      Hero hero=new Hero();
      hero.say();
      hero.speak();
   }
   
   public static void main(String[] args) 
      boolean    hasAnnotation = test.class.isAnnotationPresent(TestAnnotation.class);


      System.out.println("hasAnnotation:"+hasAnnotation);
      if(hasAnnotation){
         TestAnnotation testAnnotation = test.class.getAnnotation(TestAnnotation.class);
         //获取类的注解
         System.out.println("id:"+testAnnotation.id());
         System.out.println("msg:"+testAnnotation.msg());
      }


      try{
         Field a=  test.class.getDeclaredField("a");
         a.setAccessible(true);
         //获取一个成员变量上的注解
         Check  check=a.getAnnotation(Check.class);
         System.out.println("check===="+check);
         if(check !=null){
            System.out.println("check value:"+check.value());
         }


         Method testMethod = test.class.getDeclaredMethod("testMethod");
         if(testMethod !=null){
            //获取方法中的注解
            Annotation[] ans = testMethod.getAnnotations();
            for(int i = 0;i<ans.length;i++){
               System.out.println("method testMethod annotation:"+ans[i].annotationType().getSimpleName());
            }
         }


      }catch (NoSuchFieldException e){
         e.printStackTrace();
         System.out.println(e.getMessage());
      }catch (SecurityException e){
         e.printStackTrace();
         System.out.println(e.getMessage());
      }catch (NoSuchMethodException e){
         e.printStackTrace();
         System.out.println(e.getMessage());
      }
   }
}
运行结果如下:
id:-1
msg:hello everyone
check value:hi
method testMethod annotation:Perform
需要注意的是,如果一个注解要在运行时被成功提取,那么@Retention(RetentionPolicy.RUNTIME)是必须的。
注解的使用场景
当开发者使用了Annotation修饰了类、方法、Field等成员之后,这些Annotation不会自己生效,必须由开发者提供相应的代码来提取并处理Annotation信息。这些处理提取和处理Annotation的代码统称为APT(Annotation Processing Tool)
亲手自定义注解完成某个目的
总结:
1. 如果注解难于理解,你就把他类同于标签,标签为了解释事物,注解为了解释代码
2. 注解的基本语法,创建如同接口,单是多了个@符号
3. 注解的元注解
4. 注解的属性
5. 注解主要给编译器及工具类型的软件用的
6. 注解的提取需要借助于java的反射技术,反射比较慢,所以注解使用时也需要谨慎计较时间成本

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值