如何通过常量Java为注释提供值


146

我认为这在Java中可能无法实现,因为注释及其参数在编译时已解决。我有一个如下的界面,

public interface FieldValues {
   String[] FIELD1 = new String[]{"value1", "value2"};
}

和另一类,

@SomeAnnotation(locations = {"value1", "value2"})
public class MyClass {
   ....
}

我用注解标记了许多类,我想知道是否可以避免在每个注解中指定字符串,而宁愿使用

@SomeAnnotation(locations = FieldValues.FIELD1)
public class MyClass {
   ....
}

但是,这会产生诸如注释值之类的编译错误,该值应该是数组初始化程序等。有人知道我如何使用String常量或String []常量为注释提供值吗?

Answers:


126

编译常量只能是原语和字符串

15.28。常数表达式

编译时常量表达式是表示原始类型或String的值的表达式,该值不会突然完成,并且仅使用以下内容组成:

  • 基本类型的文字和类型的文字 String
  • 强制转换为基本类型并强制转换为类型 String
  • [...]运营商[...]
  • 用括号括起来的表达式,其中包含的表达式为常量表达式。
  • 引用常量变量的简单名称。
  • TypeName形式的合格名称。引用常量变量的标识符

实际上,在Java中,无法保护数组中的项。在运行时,任何人都可以做FieldValues.FIELD1[0]="value3",因此,如果我们更深入地研究数组,则数组不能真正恒定。


14
枚举也!:) :)
TacB0sS 2012年

1
@ TacB0sS,枚举不是常量表达式。
jaco0646

好吧...也许您应该放手让我知道...我一直都在使用它们:)
TacB0sS 2015年

4
注释下有一个更相关的规范。除了常量表达式外,注释值还可以是数组初始值设定项,类文字枚举常量
jaco0646

3
您可以enum在批注中使用@ TacB0sS ,但它们不是编译时常量。当您编写static final EnumType VARIABLE = EnumType.ENUM_CONSTANT;并尝试VARIABLE在批注中使用时,区别变得明显。它不会工作。您只能使用EnumType.ENUM_CONSTANT非常量表达式,而只能在批注(和switch语句)中使用它。
Holger

37

您可以使用常量(即静态的最终变量)作为注释的参数。举个简单的例子,我经常使用这样的方法:

import org.junit.Test;
import static org.junit.Assert.*;

public class MyTestClass
{
    private static final int TEST_TIMEOUT = 60000; // one minute per test

    @Test(timeout=TEST_TIMEOUT)
    public void testJDK()
    {
        assertTrue("Something is very wrong", Boolean.TRUE);
    }
}

请注意,可以将TEST_TIMEOUT常量直接传递到注释中。

暂时,我不记得曾经尝试过使用数组,因此您可能会遇到一些问题,与Java变量相比,数组在表示为批注参数的方式上有细微的差别吗?但是对于您问题的另一部分,您肯定可以使用常量String而不出现任何问题。

编辑:我刚刚用String数组尝试了此操作,并且没有遇到您提到的问题-但是编译器的确告诉我,尽管将数组定义为,但“属性值必须是常数” public static final String[]。也许不喜欢数组可变的事实?嗯...


1
祝我好运!哦,是的,我能够传递字符串/数字,但不能传递数组。我将花更多时间在这个问题上,如果没有解决的办法,将接受答案:)
Kannan Ekanath 2010年

是的,我的猜测是,FIELD1数组的可变性是这里的问题。您可以使用数组初始化程序声明该数组,因为其他任何人都无法访问该数组,因此以后无法更改。
ColinD 2010年

这解决了我的问题。只需在注释和代码之间共享String常量即可。谢谢!
simon 2013年

1
静态最终变量不是唯一的先决条件。如果您尝试动态计算变量,则会收到相同的错误消息。
Wolfgang Fahl

11

您没有在示例中为其提供数组。以下可以正常编译:

public @interface SampleAnnotation {
    String[] sampleValues();
}

public class Values {
    public static final String val0 = "A";
    public static final String val1 = "B";

    @SampleAnnotation(sampleValues={ val0, val1 })
    public void foo() {
    }
}

4
在示例中将为它提供一个数组,而不仅仅是在注释声明中直接创建的一个数组。
ColinD

7

有人知道我如何使用String常量或String []常量为注释提供值吗?

不幸的是,您不能对数组执行此操作。对于非数组变量,该值必须是最终静态值。


5

我认为这在Java中可能无法实现,因为注释及其参数在编译时已解决。

使用Seam 2 http://seamframework.org/,您可以在运行时解析注释参数,并在双引号内使用表达式语言。

在Seam 3 http://seamframework.org/Seam3/Solder中,此功能是模块Seam Solder


3
不,您没有在运行时解析参数。参数在编译时解析。设置它们的值时,它们随后被用来在运行时执行某些操作与字面上没有任何关系。
基金莫妮卡的诉讼

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.