深入理解Java注解

2023-05-04 20:53:11 浏览数 (1)

Java注解可以提供代码的某些信息,但并不是直接影响它所注解的代码的。

我们先了解java内置的注解使用,然后编写自定义注解,理解注解的具体使用方法,利用反射技术解析注解。

Java注解

Java注解是在1.5开始引入的,此后在java EE框架中经常使用,例如:Hibernate, Jersey, Spring 等。Java注解作为程序的元数据嵌入到代码中。注解将会被编译器解析或者通过解析器来解析,我们可以指定在编译器或者运行时让注解生效。

在注解之前,程序的元数据一般是通过java注释或者javadoc来表现,但是注解能提供更多的信息。 注解不仅仅包含程序的元数据还可以利用解析器在运行时控制程序的执行流程。

Java自定义注解

在java中创建注解类似于创建一个接口,只是在interface加了一个前缀 @,在注解中我们也可以定义方法。

先看看java中的自定义注解,再讨论它的特性以及几个重要点。

代码语言:javascript复制
package com.byron4j.hightLevel.anno;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 
 * <pre>
 *      自定义注解,可以用来注解方法
 * </pre>
 * @author Byron.Y.Y
 */
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Target(ElementType.METHOD)
public @interface MethodInfo {
    String author() default "Pankaj";
    String date();
    int revision() default 1;
    String comments();
}

java注解有几个重要的点需要了解:

  • 方法不能有参数
  • 方法的返回类型只能是原始类型、String、枚举类型、注解类型 或者 这些类型的数组形式
  • 方法可以有默认值
  • 注解也可以通过元注解附加相关信息。元数据主要提供关于当前注解的某些信息。java给我们提供了常用的几个元注解@Documented 被该注解标记的元素可以被javadoc文档化。这个类型一般用于使用在client需要使用的注解上。如果一个注解被Documented标注了,这个注解也会成为它所注解的元素的API的一部分。 @Target 表明注解能使用的元素类型,一般有TYPE(类), METHOD(方法), CONSTRUCTOR(构造器), FIELD(成员变量)等类型,如果没有指定Target则表示该注解可以使用在任何元素中。 @Inherited 表明该注解可以被自动继承。 如果该注解标记在类上,则子类会继承该注解。 @Retention 表明注解信息保留的时间。 使用RetentionPolicy的枚举类型SOURCE、CLASS 和RUNTIME

Java内置注解

java给我们提供了几个内置的注解:

  • @Override 当我们想重写父类的方法时,应该使用该注解告知编译器我们重写了该方法。如此,当父类方法移除或者变更,编译器就会提示错误信息了。所以重写一个方法的时候,我们应当使用该注解。
  • @Deprecated 当我们告知编译器该方法已经废弃了的时候,就需要使用该注解了。Java推荐在文档中提供我们为什么废弃该方法的原因以及最好提供其他的可替代方法。
  • @SuppressWarnings 告诉编译器忽略代码产生的警告。

Java注解示例

我们来了解如何在代码中使用java内置的元注解标注的自定义注解。

代码语言:javascript复制
package com.byron4j.hightLevel.anno;

import java.util.ArrayList;
import java.util.List;

/**
 * 
 * <pre>
 *      注解使用详情------注解没有指定默认值的属性在标注时一定要显示指定属性值
 * </pre>
 * @author Byron.Y.Y
 */
public class AnnotationExample {


    @MethodInfo(author="东陆之滇", comments="这是toString方法", date="2017-05-11", revision = 1)
    @Override
    public String toString() {

        System.out.println("这是重写Object的toString()方法.");
        return "这是重写Object的toString()方法.";

    }


    @MethodInfo(author="东陆之滇", comments="废弃的老方法,建议不要使用了", date="2017-05-11", revision = 1)
    @Deprecated
    public void oldMethod(){
        System.out.println("这是一个废弃的老方法,建议不要使用了.");
    }



    @SuppressWarnings({"unused", "unchecked", "rawtypes"})
    @MethodInfo(author = "东陆之滇", comments="泛型警告方法测试", date = "2017-05-11")
    public void genericsTest(){

        System.out.println("泛型警告方法测试");


        List<String> list = new ArrayList();

    }




}

上面的示例代码以及注释说明完全可以说明注解在不同用例中的用法。

Java注解解析

我们将在一个java类中通过反射技术去解析注解。但是要注意注解的保留策略(Retention Policy)应该指定为运行时RUNTIME , 否则它的信息不能在运行时被识别。这样我们就能从注解中获取信息了。

代码语言:javascript复制
package com.byron4j.hightLevel.anno;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;

/**
 * 
 * <pre>
 *      注解解析实例
 * </pre>
 * @author Byron.Y.Y
 */
public class AnnotationParsing {

    public static void main(String[] args) {

        //Level1: 遍历AnnotationExample的各个方法
        for( Method method : AnnotationExample.class.getMethods() ){

            //Level2: 检查标注了MethodInfo注解的方法,则打印该方法所有的注解类型
            if(  method.isAnnotationPresent(MethodInfo.class) ){

                for( Annotation anno : method.getAnnotations() ){

                    System.out.println("方法"   method   "标注了"   anno   "注解");

                }

                MethodInfo methodInfo = method.getDeclaredAnnotation(MethodInfo.class);

                System.out.println(method   "方法版本号为"   methodInfo.revision());

            }

        }

    }

}

输出结果为:

代码语言:javascript复制
方法public void com.byron4j.hightLevel.anno.AnnotationExample.oldMethod()标注了@com.byron4j.hightLevel.anno.MethodInfo(author=东陆之滇, revision=1, comments=废弃的老方法,建议不要使用了, date=2017-05-11)注解
方法public void com.byron4j.hightLevel.anno.AnnotationExample.oldMethod()标注了@java.lang.Deprecated()注解
public void com.byron4j.hightLevel.anno.AnnotationExample.oldMethod()方法版本号为1
方法public void com.byron4j.hightLevel.anno.AnnotationExample.genericsTest()标注了@com.byron4j.hightLevel.anno.MethodInfo(author=东陆之滇, revision=1, comments=泛型警告方法测试, date=2017-05-11)注解
public void com.byron4j.hightLevel.anno.AnnotationExample.genericsTest()方法版本号为1
方法public java.lang.String com.byron4j.hightLevel.anno.AnnotationExample.toString()标注了@com.byron4j.hightLevel.anno.MethodInfo(author=东陆之滇, revision=1, comments=这是toString方法, date=2017-05-11)注解
public java.lang.String com.byron4j.hightLevel.anno.AnnotationExample.toString()方法版本号为1

反射技术的力量是相当庞大的,被广泛用于Java EE框架中如Spring, Hibernate, JUnit等。

一个标准的JAVA枚举类

一个标准的JAVA枚举类(来源是LMAX公司的一个提供银行的小项目):

代码语言:javascript复制
/**
 * Copyright 2013 Marc Wrobel (marc.wrobel@gmail.com)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package fr.marcwrobel.jbanking;

/**
 * The countries having an ISO 3166-1-alpha-2 code.
 *
 * <p>
 * Please be advised that this list is current as of 2013/05/26. Up-to-date list can be found for free on the <a href="http://www.iso.org/iso/home/standards/country_codes.htm">
 * International Organization for Standardization website</a>.
 * </p>
 *
 * @author Marc Wrobel
 * @see <a href="http://www.iso.org/iso/home/standards/country_codes.htm">http://www.iso.org/iso/home/standards/country_codes.htm</a>
 * @since 1.0
 */
public enum IsoCountry {

    AFGHANISTAN("AF"),
    ALAND_ISLANDS("AX"),
    ALBANIA("AL"),
    ALGERIA("DZ"),
    AMERICAN_SAMOA("AS"),
    ANDORRA("AD"),
    ANGOLA("AO"),
    ANGUILLA("AI"),
    ANTARCTICA("AQ"),
    ANTIGUA_AND_BARBUDA("AG"),
    ARGENTINA("AR"),
    ARMENIA("AM"),
    ARUBA("AW"),
    AUSTRALIA("AU"),
    AUSTRIA("AT"),
    AZERBAIJAN("AZ"),
    BAHAMAS("BS"),
    BAHRAIN("BH"),
    BANGLADESH("BD"),
    BARBADOS("BB"),
    BELARUS("BY"),
    BELGIUM("BE"),
    BELIZE("BZ"),
    BENIN("BJ"),
    BERMUDA("BM"),
    BHUTAN("BT"),
    BOLIVIA("BO"),
    BONAIRE("BQ"),
    BOSNIA_AND_HERZEGOVINA("BA"),
    BOTSWANA("BW"),
    BOUVET_ISLAND("BV"),
    BRAZIL("BR"),
    BRITISH_INDIAN_OCEAN_TERRITORY("IO"),
    BRITISH_VIRGIN_ISLANDS("VG"),
    BRUNEI_DARUSSALAM("BN"),
    BULGARIA("BG"),
    BURKINA_FASO("BF"),
    BURUNDI("BI"),
    CAMBODIA("KH"),
    CAMEROON("CM"),
    CANADA("CA"),
    CAPE_VERDE("CV"),
    CAYMAN_ISLANDS("KY"),
    CENTRAL_AFRICAN_REPUBLIC("CF"),
    CHAD("TD"),
    CHILE("CL"),
    CHINA("CN"),
    CHRISTMAS_ISLAND("CX"),
    COCOS_ISLANDS("CC"),
    COLOMBIA("CO"),
    COMOROS("KM"),
    CONGO("CG"),
    COOK_ISLANDS("CK"),
    COSTA_RICA("CR"),
    COTE_D_IVOIRE("CI"),
    CROATIA("HR"),
    CUBA("CU"),
    CURACAO("CW"),
    CYPRUS("CY"),
    CZECH_REPUBLIC("CZ"),
    DENMARK("DK"),
    DJIBOUTI("DJ"),
    DOMINICA("DM"),
    DOMINICAN_REPUBLIC("DO"),
    ECUADOR("EC"),
    EGYPT("EG"),
    EL_SALVADOR("SV"),
    EQUATORIAL_GUINEA("GQ"),
    ERITREA("ER"),
    ESTONIA("EE"),
    ETHIOPIA("ET"),
    FALKLAND_ISLANDS("FK"),
    FAROE_ISLANDS("FO"),
    FIJI("FJ"),
    FINLAND("FI"),
    FRANCE("FR"),
    FRENCH_GUIANA("GF"),
    FRENCH_POLYNESIA("PF"),
    FRENCH_SOUTHERN_TERRITORIES("TF"),
    GABON("GA"),
    GAMBIA("GM"),
    GEORGIA("GE"),
    GERMANY("DE"),
    GHANA("GH"),
    GIBRALTAR("GI"),
    GREECE("GR"),
    GREENLAND("GL"),
    GRENADA("GD"),
    GUADELOUPE("GP"),
    GUAM("GU"),
    GUATEMALA("GT"),
    GUERNSEY("GG"),
    GUINEA("GN"),
    GUINEA_BISSAU("GW"),
    GUYANA("GY"),
    HAITI("HT"),
    HEARD_ISLAND_AND_MCDONALD_ISLANDS("HM"),
    HONDURAS("HN"),
    HONG_KONG("HK"),
    HUNGARY("HU"),
    ICELAND("IS"),
    INDIA("IN"),
    INDONESIA("ID"),
    IRAN("IR"),
    IRAQ("IQ"),
    IRELAND("IE"),
    ISLE_OF_MAN("IM"),
    ISRAEL("IL"),
    ITALY("IT"),
    JAMAICA("JM"),
    JAPAN("JP"),
    JERSEY("JE"),
    JORDAN("JO"),
    KAZAKHSTAN("KZ"),
    KENYA("KE"),
    KIRIBATI("KI"),
    KUWAIT("KW"),
    KYRGYZSTAN("KG"),
    LAO_PEOPLES_DEMOCRATIC_REPUBLIC("LA"),
    LATVIA("LV"),
    LEBANON("LB"),
    LESOTHO("LS"),
    LIBERIA("LR"),
    LIBYA("LY"),
    LIECHTENSTEIN("LI"),
    LITHUANIA("LT"),
    LUXEMBOURG("LU"),
    MACAO("MO"),
    MACEDONIA("MK"),
    MADAGASCAR("MG"),
    MALAWI("MW"),
    MALAYSIA("MY"),
    MALDIVES("MV"),
    MALI("ML"),
    MALTA("MT"),
    MARSHALL_ISLANDS("MH"),
    MARTINIQUE("MQ"),
    MAURITANIA("MR"),
    MAURITIUS("MU"),
    MAYOTTE("YT"),
    MEXICO("MX"),
    MICRONESIA("FM"),
    MOLDOVA("MD"),
    MONACO("MC"),
    MONGOLIA("MN"),
    MONTENEGRO("ME"),
    MONTSERRAT("MS"),
    MOROCCO("MA"),
    MOZAMBIQUE("MZ"),
    MYANMAR("MM"),
    NAMIBIA("NA"),
    NAURU("NR"),
    NEPAL("NP"),
    NETHERLANDS("NL"),
    NEW_CALEDONIA("NC"),
    NEW_ZEALAND("NZ"),
    NICARAGUA("NI"),
    NIGER("NE"),
    NIGERIA("NG"),
    NIUE("NU"),
    NORFOLK_ISLAND("NF"),
    NORTHERN_MARIANA_ISLANDS("MP"),
    NORTH_KOREA("KP"),
    NORWAY("NO"),
    OMAN("OM"),
    PAKISTAN("PK"),
    PALAU("PW"),
    PALESTINE("PS"),
    PANAMA("PA"),
    PAPUA_NEW_GUINEA("PG"),
    PARAGUAY("PY"),
    PERU("PE"),
    PHILIPPINES("PH"),
    PITCAIRN("PN"),
    POLAND("PL"),
    PORTUGAL("PT"),
    PUERTO_RICO("PR"),
    QATAR("QA"),
    REUNION("RE"),
    ROMANIA("RO"),
    RUSSIAN_FEDERATION("RU"),
    RWANDA("RW"),
    SAINT_BARTHELEMY("BL"),
    SAINT_HELENA("SH"),
    SAINT_KITTS_AND_NEVIS("KN"),
    SAINT_LUCIA("LC"),
    SAINT_MARTIN("MF"),
    SAINT_PIERRE_AND_MIQUELON("PM"),
    SAINT_VINCENT_AND_THE_GRENADINES("VC"),
    SAMOA("WS"),
    SAN_MARINO("SM"),
    SAO_TOME_AND_PRINCIPE("ST"),
    SAUDI_ARABIA("SA"),
    SENEGAL("SN"),
    SERBIA("RS"),
    SEYCHELLES("SC"),
    SIERRA_LEONE("SL"),
    SINGAPORE("SG"),
    SINT_MAARTEN("SX"),
    SLOVAKIA("SK"),
    SLOVENIA("SI"),
    SOLOMON_ISLANDS("SB"),
    SOMALIA("SO"),
    SOUTH_AFRICA("ZA"),
    SOUTH_GEORGIA_AND_THE_SOUTH_SANDWICH_ISLANDS("GS"),
    SOUTH_KOREA("KR"),
    SOUTH_SUDAN("SS"),
    SPAIN("ES"),
    SRI_LANKA("LK"),
    SUDAN("SD"),
    SURINAME("SR"),
    SVALBARD_AND_JAN_MAYEN("SJ"),
    SWAZILAND("SZ"),
    SWEDEN("SE"),
    SWITZERLAND("CH"),
    SYRIAN_ARAB_REPUBLIC("SY"),
    TAIWAN("TW"),
    TAJIKISTAN("TJ"),
    TANZANIA("TZ"),
    THAILAND("TH"),
    THE_DEMOCRATIC_REPUBLIC_OF_THE_CONGO("CD"),
    TIMOR_LESTE("TL"),
    TOGO("TG"),
    TOKELAU("TK"),
    TONGA("TO"),
    TRINIDAD_AND_TOBAGO("TT"),
    TUNISIA("TN"),
    TURKEY("TR"),
    TURKMENISTAN("TM"),
    TURKS_AND_CAICOS_ISLANDS("TC"),
    TUVALU("TV"),
    UGANDA("UG"),
    UKRAINE("UA"),
    UNITED_ARAB_EMIRATES("AE"),
    UNITED_KINGDOM("GB"),
    UNITED_STATES("US"),
    UNITED_STATES_MINOR_OUTLYING_ISLANDS("UM"),
    URUGUAY("UY"),
    US_VIRGIN_ISLANDS("VI"),
    UZBEKISTAN("UZ"),
    VANUATU("VU"),
    VATICAN_CITY_STATE("VA"),
    VENEZUELA("VE"),
    VIET_NAM("VN"),
    WALLIS_AND_FUTUNA("WF"),
    WESTERN_SAHARA("EH"),
    YEMEN("YE"),
    ZAMBIA("ZM"),
    ZIMBABWE("ZW");

    private final String code;

    private IsoCountry(String code) {
        this.code = code;
    }

    /**
     * <p>Returns this country ISO 3166-1-alpha-2 code.</p>
     *
     * @return a non null and 2 characters length string
     */
    public String getCode() {
        return code;
    }

    /**
     * <p>Translate the given ISO 3166-1-alpha-2 code to an IsoCountry.</p>
     *
     * <p>This method is not case sensitive.</p>
     *
     * @param code A non-null String.
     * @return the country having the given ISO 3166-1-alpha-2 code, or null if it does not exist
     */
    public static IsoCountry fromCode(String code) {
        String cleanedCode = (code == null ? null : code.toUpperCase());

        if (cleanedCode == null || cleanedCode.length() != 2) {
            return null;
        }

        for (IsoCountry country : values()) {
            if (country.getCode().equals(cleanedCode)) {
                return country;
            }
        }

        return null;
    }

}

0 人点赞