当前位置: 首页 > 科技观察

掌握Java注解,一夜地仙

时间:2023-03-17 19:43:05 科技观察

一、注解简介Java注解用于为Java代码提供元数据。元数据是指用来描述数据的数据。通俗地说,就是描述代码之间关系的数据,或者说代码与其他资源(如数据库表)之间的内部关系。在一些技术框架中,例如Struts和hibernate,元数据是在不知不觉中使用的。对于Struts,元数据是指struts-config.xml;对于休眠,它是hbm文件。上面描述的元数据都是基于xml文件或者其他形式的单独的配置文件。这带来了一些不便。1、与描述文件分离,不利于一致性的维护;2.所有这些文件都是没有明确类型支持的ASCII文件。基于元数据的广泛使用,JDK5.0引入了Annotation的概念来描述元数据。在Java中,元数据以标签的形式存在于Java代码中,元数据标签的存在不影响程序代码的编译和执行。总之,简而言之,注解就是标签的意思。2、如何创建注解JDK5.0出来后,Java语言中有四种类型,分别是class类、枚举enum、interface接口、注解@interface。他们处于同一水平。Java通过注解来表达元数据。packagecom.guor.ClientNew;public@interfaceMyAnnotation{//定义publicfinalstaticattributeintage=25;//定义publicabstractmethodStringname();}Java注解本质上是接口,它继承了Annotation接口。3.元注解元注解是可以注解到注解的注解,或者说元注解是可以应用到其他注解的基本注解。元标记有五种类型:@Retention、@Documented、@Target、@Inherited和@Repeatable。1、@RetentionRetention,保留期含义的中文解释当@Retention应用于注解时,说明注解的生命周期。RetentionPolicy.SOURCE注解只在源码阶段保留,编译器编译时会丢弃忽略。RetentionPolicy.CLASS注解只保留到编译时,不会加载到JVM中。RetentionPolicy.RUNTIME注解可以一直保留到程序运行时,它会被加载到JVM中。2.@Documented顾名思义,这个元注解必须和文档相关。它的作用是能够将注释中的元素包含到Javadoc中。3、@Target表示注解的使用位置。ElementType.ANNOTATION_TYPE可以注解一个注解ElementType.CONSTRUCTOR可以注解一个构造函数ElementType.FIELD可以注解一个属性ElementType.LOCAL_VARIABLE可以注解一个局部变量ElementType.METHOD可以注解一个方法ElementType.PACKAGE可以注解一个包AnnotateElementType.PARAMETER可以注解参数在一个方法中ElementType.TYPE可以注解一个类型,比如类,接口,枚举4,@Inheritedlnherited表示继承。如果一个超类被@Inherited注解注解,那么如果它的子类没有被任何注解应用,那么子类继承超类的注解。代码示例5,@RepeatableRepeatable自然意味着可重复。@Repeatable是在Java1.8中加入的,所以是一个新特性。什么样的注解会被多次应用?通常,注解的值可以同时取多个值。生活中,一个人往往有多重身份。如果我把每个身份都当成注解,应该怎么用???首先声明一个Persons类,包含所有的标识@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)public@interfacePersons{Person[]value();}这里@Target是声明Persons注解的范围,而parameterElementType.Type表示可以注解一个类型,比如类、接口、枚举等。@Retention是注解的生效时间,RetentionPolicy.RUNTIME指的是程序运行的时间。Person注解:@Repeatable(Persons.class)public@interfacePerson{Stringrole()default"";}@Repeatable中括号相当于用来保存注解内容的容器。声明一个Man类并向该类添加一些标识。@Person(role="CEO")@Person(role="husband")@Person(role="father")@Person(role="son")publicclassMan{Stringname="";}在主方法中访问它注解:publicstaticvoidmain(String[]args){Annotation[]annotations=Man.class.getAnnotations();System.out.println(annotations.length);Personsp1=(Persons)annotations[0];for(Persont:p1.value()){System.out.println(t.role());}}下面代码的输出是一样的,但是可以先判断是不是对应的注解,更加严谨。如果(Man.class.isAnnotationPresent(Persons.class)){Personsp2=Man.class.getAnnotation(Persons.class);for(Persont:p2.value()){System.out.println(t.role());}}运行结果:4.注解的属性注解的属性也叫成员变量,注解只有成员变量,没有方法。注解的成员变量在注解的定义中以“无参方法”的形式声明。方法名定义了成员变量的名称,其返回值定义了成员变量的类型。@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)public@interfaceTestAnnotation{intid();Stringmsg();}上面代码定义了注解TestAnnotation有两个属性:id和msg。在使用的时候,我们应该给它们赋值。赋值的方法是在注解的括号中使用value="",多个属性用.隔开。@TestAnnotation(id=3,msg="helloannotation")publicclassTest{}需要注意的是,在注解中定义属性时,其类型必须是8种基本数据类型加上类、接口、注解及其数组。注解中的属性可以有默认值,默认值需要用默认键值指定。例如:@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)public@interfaceTestAnnotation{publicintid()default-1;publicStringmsg()default"Nezha";}TestAnnotation中id属性的默认值为-1,而msg属性的默认值是哪吒。它可以这样应用。@TestAnnotation()publicclassTest{}有默认值,所以@TestAnnotation后面的括号里不需要赋值,这一步可以省略。除此之外,还有一种情况。如果一个注解中只有一个名为value的属性,那么在应用该注解时可以直接将属性值填入括号中。public@interfaceCheck{Stringvalue();}上面代码中,Check注解只有value属性。所以可以这样应用。@Check("嗨")inta;这和下面的@Check(value="hi")inta是一样的;最后,需要注意的另一种情况是注解没有任何属性。例如:public@interfacePerform{},应用该注解时,括号可以省略。@PerformpublicvoidtestMethod(){}5.Java自带的注解学习了上面的相关知识后,我们已经可以自己定义一个注解了。其实Java语言本身就提供了几个现成的注解。1、@Override大家应该不陌生吧。提醒子类重写父类中@Override修饰的方法。2.@Deprecated加上这个注解后,表示不再推荐这个方法或类,调用line的时候会删除,但不代表不能用,只是表示不用推荐,因为有更好的调用方法。然后直接删除?因为在一个项目中,项目比较大,代码也比较多。在后续的开发过程中,之前实现某个方法可能不是很合理。这时候需要重写一个新的方法,而前面的方法不能随便删掉,因为可能在别处调用,所以加上这个注解就OK了!3、@SuppressWarning表示防止警告。该注解的作用是向编译器提供一条指令,使带注解的代码元素内的某些警告静音。4.@SafeVarargs参数安全类型注解。它的目的是提醒开发者不要对参数做一些不安全的操作,它的存在会阻止编译器产生unchecked等警告。当声明一个带有歧义类型(如:泛型)的变量参数的构造函数或方法时,Java编译器会报未检查警告。针对这种情况,如果程序员确定声明的构造函数和方法体没有问题,可以使用@SafeVarargs来标记,这样Java编译器就不会报uncheckedwarning了!5.@FunctionalInterfaceJava8引入了函数式接口新注解@FunctionalInterface主要用于编译级错误检查。有了这个注解,当你写的接口不符合函数式接口的定义时,编译器就会报错。它们主要用在Lambda表达式和方法引用中(其实也可以认为是Lambda表达式)。如果一个函数式接口定义如下:@FunctionalInterfaceinterfaceGreetingService{voidsayMessage(Stringmessage);},那么可以用一个Lambda表达式来表示这个接口的一个实现(注:在JAVA8之前,一般都是用匿名类来实现):GreetingServicegreetService1=消息->System.out.println("你好"+消息);六、注解的使用场景1、注解的官方解释注解是一系列提供数据解释程序代码的元数据,但注解并不是代码本身的解释部分。注释对代码的工作方式没有直接影响。2、注解的用处①为编译器提供信息:编译器可以使用注解来检测错误或警告信息②编译过程中的处理:软件工具可以使用注解信息生成代码、HTML文档或进行其他响应处理。③运行时处理:一些注解可以在程序运行时接受代码抽取。值得注意的是,注释不是代码本身的一部分。3、注解使用示例publicclassExampleUnitTest{@Testpublicvoidaddition_isCorrect()throwsException{assertEquals(4,2+2);}}@Test标记要测试的方法addition_isCorrect()。还有很多注解比如ssm框架。7、注解的本质注解的本质是继承自Annotation的特殊接口,其具体实现类是Java运行时生成的动态代理类。通过代理对象调用其自定义注解的方法最终会调用AnnotationInvocationHandler的invoke方法,该方法会从memberValues映射中索引对应的值,而memberValues的来源是Java常量池。8.总结1.Annotations是标签。注释用于解释代码。2.注解@interface3的基本语法。注释的元注释4。注释的属性5。注释主要用于编译器和工具类软件6。注解的提取借助Java的反射技术,反射比较慢,所以使用注解时需要仔细计算时间成本转载本文请联系哪吒学习Java公众号。