Java 用户注释是如何工作的?

Java 用户注释是如何工作的?,java,annotations,Java,Annotations,我对Java编程还是相当陌生的,我在查看一个开源项目时遇到了这个问题 public @TileNetworkData int progressPart = 0; 我以前见过@的用法,但只是在成员面前做@覆盖之类的事情。令我惊讶的是,在查找定义时,它让我想到了用户代码 import java.lang.annotation.Inherited; import java.lang.annotation.Retention; import java.lang.annotation.Retent

我对Java编程还是相当陌生的,我在查看一个开源项目时遇到了这个问题

public @TileNetworkData int progressPart = 0;   
我以前见过
@
的用法,但只是在成员面前做
@覆盖
之类的事情。令我惊讶的是,在查找定义时,它让我想到了用户代码

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; 

}
这段代码在做什么?它有什么用处?看起来它正在向字段中添加某种形式的元数据。这样的东西怎么用


在谷歌上搜索时,我发现这被称为“注释”,但与之相关的一切都超出了我的想象。任何类似的例子都会得到赞赏。

注释用于元数据,用于描述方法、类和其他类型的对象

可以使用将元数据(数据描述)分配给java类。经典的例子是@Deprecated,它将一个方法标记为“以后不再使用”

例如,您可以使用它们向java类添加配置信息。如果您使用的是Hibernate(一种ORM),您可以向类中添加注释,说明该类应根据数据库表
table_xxx
中包含的信息填充,并且列
column_xxx
信息应存储在类中的某某字段中

您发布的代码正在定义注释。这将允许在代码中的其他地方使用此注释。这意味着注释将在运行时可用,
@Retention(RetentionPolicy.runtime)
,并且该注释应该对使用它的类和该类的任何子类都可用


有关更多信息,请参见

的答案。可以通过反射查询元数据。因此,如果代码中的某个地方有一个通用的
void submitilenetworkdata(对象模型)
,它可以迭代
model
的字段,并基于TileNetworkData注释构建一个二进制转储。

示例:事务划分:

public class TransactionalThing {
    @Transactional
    public void doSomePersistenceStuff() {
        Foo foo = loadAFoo();
        doSomeStuffWith(foo);
        foo.setProcessed(true);
    }
}
其他代码将查找由
@Transactional
注释的方法,在调用该方法之前启动事务,并在事务完成时提交(或回滚)事务。您还可以在注释中输入有关以下内容的信息,例如,回滚规则:

@Transactional(rollbackFor = SomeException.class,
               noRollbackFor = SomeOtherException.class)
同样,这取决于扫描这些事务的代码,以便读入这些属性并适当地处理事情。

被用作“机器可读元数据”——它们以编译器和运行时可以解析甚至理解的方式描述它们标记的字段、方法和类。如果您熟悉Java,您会发现Java注释的使用方式与此类似

例如,示例中定义的
TileNetworkData
注释本身用注释
Retention(RetentionPolicy.RUNTIME)
修饰。这告诉编译器将TileNetworkData注释嵌入到其注释字段的字节码中。同一注释还告诉Java运行时,当它加载带有TileNetworkData注释字段的类时,它应该保留TileNetworkData注释以进行运行时反射

现在,您的代码可以在对象的字段上进行反射,以查找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));
    }
  }
}
//我甚至还没有编译这段代码,即使它能工作,它仍然是疯狂的。
//(其他更了解注释的人可以自由编辑或替换)
public void copyTileNetworkDataToCache(对象数据、缓存){
对于(字段f:data.getClass().getFields()){
if(f.isAnnotationPresent(TileNetworkData.class)){
cache.save(f.get(data));
}
}
}

您甚至可以使用JDK 5中的
apt
前端和JDK 6及更高版本中的
javac
开关编写教Java编译器的代码。为了弥补另一个蹩脚的例子,访问tile网络可能需要很长时间,以至于您希望尽可能避免使用来自它的数据。因此,您可能希望列出包含TileNetworkData注释字段的所有类,以便可以查看所有类,并可能重写那些不一定需要访问tile网络的类。为此,您可以编写一个注释处理器,打印出所有匹配的类,然后在编译时将
apt
指向处理器。

这并不能完全回答OP的具体要求。