简体   繁体   English

用户注释如何工作?

[英]How do user annotations work?

I am still fairly new to Java programming and I was looking over a open source project and came across this 我仍然是Java编程的新手,我正在查看一个开源项目并遇到了这个问题

public @TileNetworkData int progressPart = 0;   

I have seen the use of @ before but only to do things like @override before a member. 我之前看过@的使用,但只是在成员之前做@override事情。 To my surprise looking up the definition it brought me to user code 令我惊讶的是查找了它带给我用户代码的定义

import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface TileNetworkData {

    int staticSize () default -1; 

}

What is this code doing, and what is it useful for? 这段代码在做什么,它有什么用呢? It looks like it is adding some form of metadata to the field. 看起来它正在向该字段添加某种形式的元数据。 How is something like this used? 这是怎么回事?

Doing some Googleing I found this is called "Annotations" but everything attached to it went over my head. 做一些谷歌我发现这被称为“注释”,但所有附加到它的东西都超过了我的脑海。 Any kind of example where something like this would be used would be appreciated. 任何类似于此类事例的例子都将受到赞赏。

Annotations are used as "machine-readable metadata" - they describe the fields, methods and classes they label in a way that the compiler and runtime can parse, and possibly even understand. 注释用作“机器可读元数据” - 它们以编译器和运行时可以解析甚至可能理解的方式描述它们标记的字段,方法和类。 If you are familiar with .NET's attributes , you'll find that Java annotations are used similarly. 如果您熟悉.NET的属性 ,您会发现Java注释的使用方式类似。

For example, the TileNetworkData annotation defined in your example is itself decorated with an annotation Retention(RetentionPolicy.RUNTIME) . 例如,您的示例中定义的TileNetworkData注释本身使用注释Retention(RetentionPolicy.RUNTIME)修饰。 This tells the compiler to embed the TileNetworkData annotation into the bytecode for the fields it annotates. 这告诉编译器将TileNetworkData注释嵌入到它注释的字段的字节码中。 The same annotation also tells the Java runtime that, when it loads classes with TileNetworkData-annotated fields, it should retain the TileNetworkData annotation for runtime reflection. 相同的注释也告诉Java运行时,当它使用TileNetworkData注释字段加载类时,它应该保留TileNetworkData注释以进行运行时反射。

Now, your code can reflect over fields of an object to find the TileNetworkData annotations and do something with fields so annotated: 现在,您的代码可以反映对象的字段以查找TileNetworkData注释,并对带有注释的字段执行某些操作:

// I haven't even compiled this code, and even if it works, it's still insane.
// (others who know annotations better should feel free to edit or replace)
public void copyTileNetworkDataToCache (Object data, Cache<?> cache) {
  for (Field f : data.getClass().getFields()) {
    if (f.isAnnotationPresent(TileNetworkData.class)) {
      cache.save(f.get(data));
    }
  }
}

You can even write code that teaches the Java compiler how to interpret your annotations at compile time , using the apt front end in JDK 5 and javac switches in JDK 6 and later. 您甚至可以使用JDK 5中的apt前端和JDK 6及更高版本中的javac开关编写教授Java编译器如何在编译时解释注释的代码。 To make up another lame example, accessing the tile network might take so long that you want to avoid using data from it whenever possible. 要构成另一个蹩脚的示例,访问磁贴网络可能需要很长时间,以至于您希望尽可能避免使用来自它的数据。 Hence, you might want to make a list of all classes that include TileNetworkData-annotated fields, so you can review them all and possibly rewrite the ones that don't absolutely need to access the tile network. 因此,您可能希望列出包含TileNetworkData-annotated字段的所有类,因此您可以查看所有类,并可能重写那些不一定需要访问tile网络的类。 To do this, you might write an annotation processor that prints out all matching classes, then point apt at the processor when you compile. 为此,您可以编写一个注释处理器,打印出所有匹配的类,然后在编译时指向处理器的apt

Example: Transaction demarcation: 示例:事务划分:

public class TransactionalThing {
    @Transactional
    public void doSomePersistenceStuff() {
        Foo foo = loadAFoo();
        doSomeStuffWith(foo);
        foo.setProcessed(true);
    }
}

There would be other code that looks for methods annotated by @Transactional , starts a transaction before the method is called, and commits (or rolls back) the transaction when it finishes. 还有其他代码可以查找@Transactional注释的方法,在调用方法之前启动事务,并在事务完成时提交(或回滚)事务。 You can also put information in the annotation about things like, for example, rollback rules: 您还可以在注释中添加有关诸如回滚规则之类的信息:

@Transactional(rollbackFor = SomeException.class,
               noRollbackFor = SomeOtherException.class)

And again, it's just up to the code that scans these transactions to read in those attributes and handle things appropriately. 再一次,只需要扫描这些事务的代码来读取这些属性并适当地处理事情。

Annotations are used for meta-data, to describe methods, classes and other types of object. 注释用于元数据,用于描述方法,类和其他类型的对象。

You can use the to assign meta-data (descriptions of the data) to your java classes. 您可以使用它将元数据(数据描述)分配给您的java类。 The classic example is @Deprecated , which marks a method as 'not to be used in future'. 经典的例子是@Deprecated ,它将方法标记为“将来不再使用”。

For example, you can use them to add configuration information to a java class. 例如,您可以使用它们将配置信息添加到java类。 If you're using Hibernate (an ORM), you add Annotations to the class saying that this class should be populated from information contained in the database table table_xxx , and the column column_xxx information should be stored in such and such field in the class. 如果您正在使用Hibernate(ORM),则向类中添加注释,说明应该从数据库表table_xxx包含的信息填充table_xxx ,并且列column_xxx信息应存储在类中的此类字段中。

The code that you've posted is defining the Annotation. 您发布的代码是定义注释。 This will allow this Annotation to be used elsewhere in your code. 这将允许此注释在代码中的其他位置使用。 It's saying that the annotation will be available at runtime, @Retention(RetentionPolicy.RUNTIME) , and that Annotation should be available both to the class that uses it and any sub-classes of that class. 它表示注释将在运行时可用, @Retention(RetentionPolicy.RUNTIME) ,并且Annotation应该对使用它的类和该类的任何子类都可用。

For more information, see the answers to How and where are Annotations used in Java? 有关更多信息,请参阅Java中使用的注释的方式和位置的答案

The meta data can be queried through reflection. 可以通过反射查询元数据。 Thus, if there was a generic void submitTileNetworkData(Object model) somewhere in the code it could iterate over fields of model and construct a binary dump based on TileNetworkData annotations. 因此,如果在代码中的某处存在通用的void submitTileNetworkData(Object model) ,它可以迭代model字段并基于TileNetworkData注释构造二进制转储。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM