Java注释教程– ULTIMATE指南(PDF下载)

编者注:在本文中,我们提供了全面的Java注释教程。 Java中的注释是一项主要功能,每个Java开发人员都应该知道如何使用它们。

我们在Java Code Geeks上提供了许多教程,例如创建自己的Java注释带有自定义注释的Java注释教程Java注释:探究和解释

我们还精选了各种库中使用的注释的文章,包括使您的Spring Security @Secured注释更加DRYJava注释以及真实的Spring示例

现在,是时候在一个参考文章下收集有关注释的所有信息,以使您阅读愉快。 请享用!

在本文中,我们将解释什么是Java批注,它们如何工作以及使用Java中的批注可以完成的工作。

我们将立即显示Java附带的注释,也称为“内置注释”或“元注释”,以及Java 8中与之相关的新功能。

最后,我们将实现一个自定义注释和一个处理器应用程序(消费者),该应用程序将使用Java中的反射来使用注释。

我们将基于Junit,JAXB,Spring和Hibernate等注释列出一些非常知名且使用广泛的库。

在本文的最后,您可以找到一个压缩文件,其中包含本教程中显示的所有示例。 在这些示例的实现中,使用了以下软件版本:

  • 蚀月神4.4
  • JRE更新8.20
  • Junit 4
  • 休眠4.3.6
  • FindBugs 3.0.0

1.为什么要注释?

注释已经在Java的J2SE更新5中引入,主要原因是需要提供一种机制,允许程序员直接在代码本身中编写有关其代码的元数据。

在注释之前,程序员描述代码的方式尚未标准化,每个开发人员都以自己的原始方式来做到这一点:使用瞬态关键字,通过注释,带有接口等。这不是一个好的方法,因此做出了决定:元数据的形式将在Java中可用,并引入了注释。

其他情况也有助于做出该决定:当时,XML被用作不同类型应用程序的标准代码配置机制。 由于代码与XML之间的去耦(XML不是代码!)以及这种分离的应用程序的未来维护,因此这并不是最佳方法。 还有其他原因,例如自Java更新4起,在Javadocs中使用保留字“ @deprecated”(带有小d),我非常确定这是使用“ @”的当前注释语法的原因之一。 ”。

注释设计和开发中涉及的主要Java规范请求是:

2.简介

解释注释是什么的最好方法是“元数据”一词:包含有关自身信息的数据。 注释是代码元数据。 它们包含有关代码本身的信息。

注释可以在包,类,方法,变量和参数中使用。 由于Java 8注释几乎可以放置在代码的每个位置,因此称为类型注释。 我们将在本教程中更详细地介绍这一点。

带注释的代码不受其注释的直接影响。 这些仅将有关其的信息提供给可能出于不同目的使用(或不使用)注释的第三系统。

注释被编译在类文件中,并且可以在运行时检索,并由使用者或处理器出于某种逻辑目的使用。 也可以创建在运行时不可用的注释,甚至可以创建仅在源代码中而不在编译时可用的注释。

3.消费者

可能很难理解注释的目的和用途,它们不包含任何功能逻辑,并且不影响注释的代码,它们的作用是什么?

这就是我所说的注释使用者。 这些是利用注释的代码并根据注释信息执行不同动作的系统或应用程序。

例如,对于内置注释(元注释)和标准Java一起使用的情况,使用者是执行注释代码的Java虚拟机(JVM)。 它们是我们在本教程后面将要看到的其他示例,例如Junit,消费者是Junit处理器,它读取并分析带注释的测试类,并例如根据注释决定单元测试的顺序。每次测试之前或之后要执行的操作或将要执行的方法。

我们将在Junit相关章节中更详细地介绍这一点。

消费者使用Java中的反射来读取和分析带注释的源代码。 用于此目的的主要软件包是java.langjava.lang.reflect 。 我们将在本教程中说明如何使用反射从头创建自定义使用者。

4.注释语法和注释元素

使用字符“ @”作为注释名称的前缀来声明注释。 这表明编译器该元素是注释。 一个例子:

@Annotation
public void annotatedMehod() {
...
 }

上面的注释称为“ Annotation”,并且正在注释方法annotatedMethod() 。 编译器会处理它。

注释具有键值形式的元素。 这些“元素”是注释的属性。

@Annotation(
   info = "I am an annotation",
   counter = "55"
)
public void annotatedMehod() {
...
 }

如果注释中仅包含一个元素(或者仅需要指定一个元素,因为其余元素具有默认值),我们可以执行以下操作:

@Annotation("I am an annotation")
public void annotatedMehod() {
...
 }

如我们在第一个示例中看到的那样,如果不需要指定任何元素,则不需要括号。

一个元素可以有多个注释,在这种情况下,一个类可以是:

@ Annotation (info = "U a u O")
@ Annotation2
class AnnotatedClass { ... }

Java提供一些现成的注释。 这些称为内置注释。 也可以定义自己的注释,这些注释称为自定义注释。 我们将在下一章中看到这些。

5.哪里可以使用

注释基本上可以在Java程序的几乎每个元素中使用:类,字段,方法,包,变量等。

从Java 8开始,可以使用按类型注释的概念。 在Java 8之前,注释只能用于前面列出的元素的声明中。 在Java 8之后,也可以在类型声明中使用注释。 现在可以使用以下内容:

@MyAnnotation String str = "danibuiza";

我们将在与Java 8批注相关的章节中更详细地介绍这种机制。

6.用例

注释可以用于许多不同的目的,最常见的是:

  • 给编译器的信息:编译器可以使用批注根据不同的规则生成警告甚至错误。 Java 8 @FunctionalInterface批注就是这种用法的一个例子。 这使编译器可以验证带注释的类,并检查它是否是正确的功能接口。
  • 文档:软件应用程序可以使用注释来度量代码的质量,例如FindBugs或PMD,或者自动生成报告(例如Jenkins,Jira或Teamcity)。
  • 代码生成:注释可用于使用代码中存在的元数据信息自动生成代码或XML文件。 JAXB库就是一个很好的例子。
  • 运行时处理:在运行时检查的注释可用于不同的目标,例如单元测试(Junit),依赖项注入(Spring),验证,日志记录(Log4J),数据访问(Hibernate)等。

在本教程中,我们将展示批注的几种可能用法,并展示众所周知的Java库如何使用它们。

7.内置注释

Java语言带有一组默认注释。 在本章中,我们将解释最重要的那些。 值得一提的是,该列表仅涉及Java语言的核心软件包,并不包括标准JRE(如JAXB或Servlet规范)中可用的所有软件包和库。

以下某些标准注释称为元注释; 它们的目标是其他注释,并包含有关它们的信息:

  • @Retention :此注释注释其他注释,用于指示如何存储标记的注释。 此注释是一种元注释,因为它标记了注释并告知其性质。 可能的值为:
    • SOURCE :指示此注释被编译器和JVM忽略(在运行时不可用),并且仅保留在源代码中。

在本教程中,我们将看到此注释的几个示例。

  • @Target :这限制了可以应用注释的元素。 只能使用一种类型。 以下是可用类型的列表:
    • ANNOTATION_TYPE表示可以将注释应用于其他注释。
  • @Documented :将使用Javadoc工具记录带注释的元素。 默认情况下,未记录注释。 该注释可以应用于其他注释。
  • @Inherited :默认情况下,子类不继承注释。 该注释标记了一个注释,以自动继承扩展了带注释的类的所有子类。 该注释可以应用于类元素。
  • @Deprecated :指示不应使用带注释的元素。 该注释使编译器生成警告消息。 可以应用于方法,类和字段。 使用此批注时,将说明为何不推荐使用此元素,并提供替代用法。
  • @SuppressWarnings :指示编译器出于特定原因不产生警告。 例如,如果我们由于未使用私有方法而不想收到警告,则可以编写如下内容:
@SuppressWarnings( "unused")
private String myNotUsedMethod(){
	...
}

通常,如果不使用此方法,编译器会产生警告。 使用此注释可防止该行为。 该注释需要避免带有警告类别的一个或多个参数。

  • @Override :指示编译器该元素正在覆盖超类的元素。 覆盖元素时,该注释不是强制性的,但是当覆盖未正确完成时,例如子类方法的参数与父类的参数不同,或者返回类型不匹配时,它可以帮助编译器生成错误。 。
  • @SafeVarargs :断言方法或构造函数的代码不会对其参数执行不安全的操作。 将来的Java语言版本将使编译器在使用此批注时可能发生不安全操作的情况下在编译时产生错误。 有关这一信息的更多信息,请访问http://docs.oracle.com/javase/7/docs/api/java/lang/SafeVarargs.html

8. Java 8和注释

Java 8具有几个优点。 注释框架也得到了改进。 在本章中,我们将解释并提供Java第八次更新中引入的3个主要主题的示例: @Repeatable批注,类型批注声明的引入和功能接口批注@FunctionalInterface (与Lambdas结合使用)。

  • @Repeatable :指示可以用同一注解对这个注解进行@Repeatable注释。

这是用法示例。 首先,我们为注解创建一个容器,该容器将要重复或可以重复:

/**
 * Container for the {@link CanBeRepeated} Annotation containing a list of values
*/
@Retention( RetentionPolicy.RUNTIME )
@Target( ElementType.TYPE_USE )
public @interface RepeatedValues
{
    CanBeRepeated[] value();
}

然后,我们创建注释本身,并使用Meta注释@Repeatable对其进行标记:

@Retention( RetentionPolicy.RUNTIME )
@Target( ElementType.TYPE_USE )
@Repeatable( RepeatedValues.class )
public @interface CanBeRepeated
{

    String value();
}

最后,我们可以看到如何在给定的类中重复使用它:

@CanBeRepeated( "the color is green" )
@CanBeRepeated( "the color is red" )
@CanBeRepeated( "the color is blue" )
public class RepeatableAnnotated
{

}

如果我们尝试对不可重复的注释执行相同的操作:

@Retention( RetentionPolicy.RUNTIME )
@Target( ElementType.TYPE_USE )
public @interface CannotBeRepeated
{

    String value();
}

@CannotBeRepeated( "info" )
/*
 * if we try repeat the annotation we will get an error: Duplicate annotation of non-repeatable type
 * 
 * @CannotBeRepeated. Only annotation types marked
 * 
 * @Repeatable can be used multiple times at one target.
 */
// @CannotBeRepeated( "more info" )
public class RepeatableAnnotatedWrong
{

}

我们会从编译器得到如下错误:

Duplicate annotation of non-repeatable type
  • 由于Java 8也可以在类型内使用注释。 在任何可以使用类型的地方,包括new运算符,强制类型转换,实现和throws子句。 类型注释可以改进对Java代码的分析,并可以确保更强大的类型检查。 以下示例阐明了这一点:
@SuppressWarnings( "unused" )
public static void main( String[] args )
{
	// type def
	@TypeAnnotated
	String cannotBeEmpty = null;

	// type
	List<@TypeAnnotated String> myList = new ArrayList<String>();

	// values
	String myString = new @TypeAnnotated String( "this is annotated in java 8" );

}

// in method params
public void methodAnnotated( @TypeAnnotated int parameter )
{
	System.out.println( "do nothing" );
}

在Java 8之前,所有这些都是不可能的。

  • @FunctionalInterface :此注释指示被注释的元素将是一个功能接口。 功能接口是只有一种抽象方法(没有默认方法)的接口。 编译器会将带注释的元素作为功能接口进行处理,如果该元素不符合所需的要求,则会产生错误。 这是功能接口注释的示例:
// implementing its methods
@SuppressWarnings( "unused" )
MyCustomInterface myFuncInterface = new MyCustomInterface()
{

	@Override
	public int doSomething( int param )
	{
		return param * 10;
	}
};

// using lambdas
@SuppressWarnings( "unused" )
	MyCustomInterface myFuncInterfaceLambdas = ( x ) -> ( x * 10 );
}

@FunctionalInterface
interface MyCustomInterface
{
/*
 * more abstract methods will cause the interface not to be a valid functional interface and
 * the compiler will thrown an error:Invalid '@FunctionalInterface' annotation;
 * FunctionalInterfaceAnnotation.MyCustomInterface is not a functional interface
 */
	// boolean isFunctionalInterface();

	int doSomething( int param );
}

该注释可以应用于类,接口,枚举和注释,并且由JVM保留并在运行时可用。 这是它的声明:

@Documented
 @Retention(value=RUNTIME)
 @Target(value=TYPE)
public @interface FunctionalInterface

有关此注释的更多信息,请参见http://docs.oracle.com/javase/8/docs/api/java/lang/FunctionalInterface.html

9.自定义注释

正如我们在本教程中多次提到的那样,可以定义和实现自定义注释。 在本章中,我们将展示如何执行此操作。

首先,定义新的注释:

public @interface CustomAnnotationClass

这将创建一种称为CustomAnnotationClass的新型注释。 用于此目的的特殊单词是@interface,它表示自定义注释的定义。

此后,您需要为此注释定义两个强制属性,保留策略和目标。 在这里可以定义其他属性,但这是最常见和重要的属性。 它们以注解的注解形式声明,并在“内置注解”一章中进行了描述,因为它们是Java附带的注解。

因此,我们为新的自定义批注定义了以下属性:

@Retention( RetentionPolicy.RUNTIME )
@Target( ElementType.TYPE )
public @interface CustomAnnotationClass implements CustomAnnotationMethod

使用保留策略RUNTIME我们向编译器指示该注释应由JVM保留,并且可以在运行时使用反射对其进行分析。 对于元素类型TYPE我们指示此注释可以应用于类的任何元素。

然后,我们为该注释定义几个属性:

@Retention( RetentionPolicy.RUNTIME )
@Target( ElementType.TYPE )
public @interface CustomAnnotationClass
{

    public String author() default "danibuiza";

    public String date();

}

上面我们刚刚定义了属性作者,其默认值为“ danibuiza”,属性日期为默认值。 我们应该提到,所有方法声明都不能具有参数,并且不允许具有抛出子句。 返回类型仅限于前面提到的类型的String,Class,枚举,注释和数组。

现在,我们可以通过以下方式使用新创建的自定义注释:

@CustomAnnotationClass( date = "2014-05-05" )
public class AnnotatedClass
{ 
...
}

以类似的方式,我们可以使用目标METHOD创建要在方法声明中使用的注释:

@Retention( RetentionPolicy.RUNTIME )
@Target( ElementType.METHOD )
public @interface CustomAnnotationMethod
{
    
    public String author() default "danibuiza";

    public String date();

    public String description();

}

可以在以下方法声明中使用此代码:

@CustomAnnotationMethod( date = "2014-06-05", description = "annotated method" )
public String annotatedMethod()
    {
        return "nothing niente";
}

@CustomAnnotationMethod( author = "friend of mine", date = "2014-06-05", description = "annotated method" )
public String annotatedMethodFromAFriend()
{
        return "nothing niente";
}

自定义批注可以使用许多其他属性,但是目标和保留策略是最重要的属性。

10.检索注释

Java反射API包含几种方法,可用于在运行时中从类,方法和其他元素中检索注释。

包含所有这些方法的接口是AnnotatedElement ,最重要的是:

  • getAnnotations() :返回给定元素的所有注释,以及未在元素定义中明确定义的注释。
  • isAnnotationPresent(annotation) :检查传递的注释在当前元素中是否可用。
  • getAnnotation(class) :检索作为参数传递的特定注释。 如果给定元素不存在此批注,则返回null。

该类由java.lang.Classjava.lang.reflect.Methodjava.lang.reflect.Field等实现,因此基本上可以与任何类型的Java元素一起使用。

现在,我们将看到一个示例,该示例如何使用上面列出的方法读取类或方法中存在的注释:

我们编写了一个程序,尝试读取类及其方法中存在的所有注释(在本示例中,我们使用之前定义的类):

public static void main( String[] args ) throws Exception
{

	Class<AnnotatedClass> object = AnnotatedClass.class;
	// Retrieve all annotations from the class
	Annotation[] annotations = object.getAnnotations();
	for( Annotation annotation : annotations )
	{
		System.out.println( annotation );
	}

	// Checks if an annotation is present
	if( object.isAnnotationPresent( CustomAnnotationClass.class ) )
	{

		// Gets the desired annotation
		Annotation annotation = object.getAnnotation( CustomAnnotationClass.class );

		System.out.println( annotation );

	}
	// the same for all methods of the class
	for( Method method : object.getDeclaredMethods() )
	{

		if( method.isAnnotationPresent( CustomAnnotationMethod.class ) )
		{

			Annotation annotation = method.getAnnotation( CustomAnnotationMethod.class );

			System.out.println( annotation );

		}

	}
}

该程序的输出为:

@com.danibuiza.javacodegeeks.customannotations.CustomAnnotationClass(getInfo=Info, author=danibuiza, date=2014-05-05)

@com.danibuiza.javacodegeeks.customannotations.CustomAnnotationClass(getInfo=Info, author=danibuiza, date=2014-05-05)

@com.danibuiza.javacodegeeks.customannotations.CustomAnnotationMethod(author=friend of mine, date=2014-06-05, description=annotated method)
@com.danibuiza.javacodegeeks.customannotations.CustomAnnotationMethod(author=danibuiza, date=2014-06-05, description=annotated method)

在上面的程序中,我们可以看到getAnnotations()方法的用法,以便检索给定对象(方法或类)的所有注释。 我们还展示了如何使用isAnnotationPresent()getAnnotation()方法检查是否存在特定注释,并在肯定的情况下对其进行检索。

11.注释中的继承

注释可以在Java中使用继承。 这种继承与我们在面向对象的编程语言中通过继承所了解的东西没有或几乎没有共同点,在这种语言中,继承的类从其父类或接口继承方法,元素和行为。

如果注释被标记为在Java中继承,则使用保留的注释@Inherited表示被注释的类将自动将此注释传递给其子类,而无需在子类中声明该注释。 默认情况下,扩展超类的类不会继承其注释。 这完全符合注释的目的,即提供有关注释中的代码的信息,而不修改其行为。

我们将使用一个使事情变得更清楚的示例来看到这一点。 首先,我们定义一个自动使用继承的自定义注释

@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface InheritedAnnotation
{

}

我们有一个名为AnnotatedSuperClass的超类,上面声明了@InheritedAnnotation批注:

@InheritedAnnotation 
public class AnnotatedSuperClass
{

    public void oneMethod()
    {

    }

}

扩展此子类的子类:

public class AnnotatedSubClass extends AnnotatedSuperClass
{

    @Override
    public void oneMethod(){
        
    }
    
}

上面显示的子类AnnotatedSubClass将自动继承注释@InheritedAnnotation 。 我们可以通过在每个类中使用isAnnotationPresent()方法进行以下测试来看到这一点:

System.out.println( "is true: " + AnnotatedSuperClass.class.isAnnotationPresent( InheritedAnnotation.class ) );
        
System.out.println( "is true: " + AnnotatedSubClass.class.isAnnotationPresent( InheritedAnnotation.class ) );

这些行的输出是:

is true: true
is true: true

我们可以看到子类如何自动继承注释,而无需对其进行声明。

如果我们尝试在这样的界面中使用这种注释:

@InheritedAnnotation
public interface AnnotatedInterface
{

    public void oneMethod();

}

一个实现:

public class AnnotatedImplementedClass implements AnnotatedInterface
{

    @Override
    public void oneMethod()
    {

    }

}

然后,我们使用isAnnotationPresent()方法检查注释继承的结果:

System.out.println( "is true: " + AnnotatedInterface.class.isAnnotationPresent( InheritedAnnotation.class ) );
        
System.out.println( "is true: " + AnnotatedImplementedClass.class.isAnnotationPresent( InheritedAnnotation.class ) );

上一个程序的结果将是

is true: true
is true: false

这显示了继承如何与注释和接口一起工作:只是被忽略了。 尽管实现类是继承注释,但它并不继承该注释。 它仅适用于上述AnnotatedSubClass类的类。

@Inherited批注仅适用于类,并且接口中存在的批注在实现类中无效。 方法,变量,包等也会发生同样的情况。只有类可以与此注释一起使用。
@Inherited批注的Javadoc中可以找到一个很好的解释: http : //docs.oracle.com/javase/7/docs/api/java/lang/annotation/Inherited.html

注释不能从其他注释继承。 如果您尝试执行此操作,则会收到编译错误:

Annotation type declaration cannot have explicit superinterfaces

12.使用注释的已知库

在本章中,我们将展示众所周知的Java库如何使用注释。 JAXB,Spring Framework,Findbugs,Log4j,Hibernate和Junit等几个库(列表可以是无限的)将它们用于多种不同的事情,例如代码质量分析,单元测试,XML解析,依赖项注入等。

在本教程中,我们将展示其中一些用例:

朱尼特

该框架用于Java中的单元测试。 自从版本4开始,注释已被广泛使用,并且是Junit设计的Struts之一。

基本上,Junit处理器使用反射方式读取可能包含单元测试的类和套件,并根据每个方法或类开头的注释来执行它们。 有Junit批注可以修改测试的执行方式。 其他则完全用于测试执行,防止执行,更改执行顺序等。

可能的注释列表非常大,但是我们将在这里看到最重要的注释:

  • @Test :此注释指示Junit注释方法必须作为单元测试执行。 它仅适用于方法(使用目标元素类型METHOD ),并在运行时由Java虚拟机保留(使用保留策略RUNTIME)。
@Test
public void testMe()
{
	//test assertions
	assertEquals(1,1);
}

在上面的示例中,我们可以看到如何在Junit中使用这种注释。

  • @Before :before注释用于指示Junit标记的方法应在每次测试之前执行。 这对于初始化测试上下文的设置方法非常有用。 仅适用于方法:
@Before
public void setUp()
 {
	// initializing variables
	count = 0;
	init();

}
  • @After :此批注用于指示Junit处理器,应在每次单元测试后执行所有标记的方法。 此批注通常用于销毁,关闭或完成清理和重置资源的方法:
@After
public void destroy()
{
	// closing input stream
	stream.close();
}
  • @Ignore :这表明Junit不应将标记的方法作为单元测试执行。 即使它们被注释为测试。 应该忽略它们:
@Ignore
@Test
public void donotTestMe()
{
	count = -22;
	System.out.println( "donotTestMe(): " + count );
}

在开发和调试阶段应使用此方法,但是一旦代码准备投入生产,通常不留被忽略的测试。

  • @FixMethodOrder :指示应使用哪种执行顺序,通常Junit处理器会处理此问题,并且默认执行顺序对于程序员是完全未知且随机的。 确实不建议使用此批注,因为Junit方法和测试应完全相互独立,并且执行顺序不应影响结果。 但是,在某些情况下,单元测试的顺序应遵循一些规则,在这种情况下此批注可能会非常有用。
@FixMethodOrder( MethodSorters.NAME_ASCENDING )
public class JunitAnnotated

还有其他测试套件和库,它们利用MockitoJMock之类的注释,其中注释用于创建测试对象和方法期望。

有关Junit中可用注释的完整列表,请访问https://github.com/junit-team/junit/wiki/入门。

休眠ORM

Hibernate可能是Java中对象关系映射最常用的库。 它提供了映射对象模型和关系数据库的框架。 它在设计中使用了注释。

在本章中,我们将看到Hibernate提供的几个注释,并解释其处理器如何处理它们。

以下是具有注释的@Entity@Table 。 这些用于指示使用者(Hibernate处理器)带注释的类是实体Bean,并指示应为该类的对象使用哪个SQL表。 实际上,此注释仅说明了哪个是主表。 辅助元素也有注释。

@Entity
@Table( name = "hibernate_annotated" )
public class HibernateAnnotated

在下面的代码中,我们演示如何指示Hibernate处理器:标记的元素是名称为“ id”的表ID,并且应自动生成(典型的自动增量SQL ID):

@Id
@GeneratedValue
@Column( name = "id" )
private int    id;

为了指定标准的SQL表列,我们可以在元素之前编写如下代码:

@Column( name = "description" )
private String description;

这表示在类开头指定的表中,标记的元素是名称为“ description”的列。

这些注释属于Java Enterprise Edition中的http://docs.oracle.com/javaee/6/api/javax/persistence/package-summary.html程序包,基本上,它涵盖了休眠使用的所有可用注释(或位于最不常见的)。

SpringMVC

Spring是一个广泛用于实现Java Enterprise应用程序的框架。 它最重要的功能之一是在Java程序中使用依赖项注入。

Spring使用注释来替代基于XML的配置(第一个Spring版本仅使用基于XML的配置)。 目前,这两个选项都可用; 您可以使用注释和XML配置文件来配置项目。 我认为这两种方法都有好处和不便之处。

在这里,我们将展示Spring中可用的多个注释中的两个。 在以下示例中:

@Component
public class DependencyInjectionAnnotation
{

    private String description;

    public String getDescription()
    {
        return description;
    }

    @Autowired
    public void setDescription( String description )
    {
        this.description = description;
    }

}

在上面的代码段中,我们可以找到两种分别应用于整个类和方法的注释:

  • @Component :指示此注释标记的元素(在本例中为类)是自动检测的候选对象。 这意味着带注释的类可能是bean,并且Spring容器应将其考虑在内。
  • @Autowired :Spring容器将尝试在此setter方法上执行byType自动连接(这是一种使用元素类型进行属性匹配)。 它也可以应用于构造函数和属性,并且在这些情况下Spring容器采取的操作是不同的。

有关一般情况下依赖注入和Spring框架的更多信息,请访问: http : //projects.spring.io/spring-framework/

虫子

使用该库是为了测量代码的质量并提供改进它的可能性的列表。 它根据预定义(或自定义)质量违规列表检查代码。 Findbugs提供了注释列表,使程序员可以更改其默认行为。

Findbugs主要使用反射来读取代码(及其包含的批注),并决定应根据代码采取什么措施。

一个示例是注释edu.umd.cs.findbugs.annotations.SuppressFBWarnings ,它希望将违例键作为参数(必须提供一个或多个值作为参数,不需要键,因为它是默认的“值”键)。 它与java.lang.SuppressWarnings非常相似。 它用于指示Findbugs处理器在执行代码分析时忽略特定的违规行为。

这是一个使用示例:

@SuppressFBWarnings( "HE_EQUALS_USE_HASHCODE" )
public class FindBugsAnnotated
{

    @Override
    public boolean equals( Object arg0 )
    {
        return super.equals( arg0 );
    }

}

上面的类重写Object类的equals()方法,但对hashCode()方法不做同样的处理。 这通常是一个问题,因为在将元素用作HashMap键时, hashCode()equals()都应覆盖二者,以免出现问题。 因此,Findbugs将在违规报告中为其创建错误条目。

如果注释@SuppressFBWarnings的值不为HE_EQUALS_USE_HASHCODE ,则FindBugs处理器将引发以下类型的错误:

Bug: com.danibuiza.javacodegeeks.findbugsannotations.FindBugsAnnotated defines equals and uses Object.hashCode()
Bug: com.danibuiza.javacodegeeks.findbugsannotations.FindBugsAnnotated defines equals and uses Object.hashCode()

此类重写equals(Object) ,但不会覆盖hashCode() ,并且继承的实施hashCode()java.lang.Object (返回标识哈希码,由VM分配给该对象的任意的值)。 因此,该类很可能违反不变的条件,即相等的对象必须具有相等的哈希码。

如果您不希望将此类的实例插入到HashMap / HashTable ,则建议使用的hashCode实现是:

public int hashCode() {
  assert false : "hashCode not designed";
  return 42; // any arbitrary constant will do
  }
Rank: Troubling (14), confidence: High
Pattern: HE_EQUALS_USE_HASHCODE 
Type: HE, Category: BAD_PRACTICE (Bad practice)

该错误包含对该问题的解释并提供有关解决方法的提示。 在这种情况下,解决方案基本上也要实现hashCode()方法。

有关可在SuppressFBWarnings注释http://findbugs.sourceforge.net/bugDescriptions.html中用作值的所有FindBugs违规的完整列表。

杰克斯

JAXB是一个库,用于将XML文件转换和映射为Java对象,反之亦然。 实际上,该库随标准JRE一起提供,因此无需下载或以任何方式对其进行配置。 通过将包中的类导入应用程序中的javax.xml.bind.annotation中,可以直接使用它。

JAXB使用注释来通知其处理器(或JVM)XML到代码的转换(反之亦然)。 例如,有一些注释用于指示代码中的XML节点,XML属性,值等。我们将看到一个示例:

首先,我们声明一个类,指示它应该是XML中的一个节点:

import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
@XmlType( propOrder = { "brand", "model", "year", "km" } )
@XmlRootElement( name = "Car" )
class Car
...

这里使用的注释是@XmlType@XmlRootElement 。 它们通知JAXB处理器,类Car将成为转换结果所生成的XML中的一个节点。 @XmlType指示结果XML中属性的顺序。 JAXB将基于这些注释执行适当的操作。

除了用于所需属性的设置器和获取器之外,此类中无需其他任何东西即可将其用于转换。 现在我们需要一个消费者程序来执行到XML的转换:

Car car = new Car();
car.setBrand( "Mercedes" );
car.setModel( "SLK" );
car.setYear( 2011 );
car.setKm( 15000 );

Car carVW = new Car();
carVW.setBrand( "VW" );
carVW.setModel( "Touran" );
carVW.setYear( 2005 );
carVW.setKm( 150000 );

/* init jaxb marshaler */
JAXBContext jaxbContext = JAXBContext.newInstance( Car.class );
Marshaller jaxbMarshaller = jaxbContext.createMarshaller();

/* set this flag to true to format the output */
jaxbMarshaller.setProperty( Marshaller.JAXB_FORMATTED_OUTPUT, true );

/* marshaling of java objects in xml (output to standard output) */
jaxbMarshaller.marshal( car, System.out );
jaxbMarshaller.marshal( carVW, System.out );

该程序的输出将类似于:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Car>
    <brand>Mercedes</brand>
    <model>SLK</model>
    <year>2011</year>
    <km>15000</km>
</Car>
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Car>
    <brand>VW</brand>
    <model>Touran</model>
    <year>2005</year>
    <km>150000</km>
</Car>

有一个注释列表,可以在JAXB中用于XML到Java的转换。 可以在https://jaxb.java.net/中找到更多信息。

13.总结

在本文中,我们解释了自更新5以来,Java中的注释是一项非常重要的功能,并且列出了几种可以使用它们的用例。 注释基本上是包含有关已标记代码的信息的元数据。 它们不会以任何含义改变或影响代码,并且可以被称为消费者的第三个应用程序使用,以便通过反射来分析代码。

我们列出了内置的可用每默认在Java中,像有些人也称为元注解注释@Target@Retention ,或其他类似@Override@SuppressWarnings ,并现身在Java中8的新功能涉及到像注释@Repeteable注释, @FunctionalInterface @Repeteable注释和按类型注释。

我们还展示了一些将注释与反射结合使用的代码示例,并且我们提到并描述了一些现实生活中的库,这些库在Java中广泛使用注释,例如Junit,Spring或Hibernate。

注释是Java中一种非常强大的机制,可以分析任何类型的程序的元数据,并且可以应用于不同的范围,例如验证,依赖项注入或单元测试。

14.下载Java注释教程源代码

这是Java注释教程。

下载
您可以在此处下载本教程的完整源代码: customAnnotations

15.资源

这是与Java批注相关的非常有用的资源列表:

翻译自: https://www.javacodegeeks.com/2014/11/java-annotations-tutorial.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值