我在Scala中的meta-annotations遇到了一些麻烦。假设有一个类
private class MyClass(@(volatile @field) private[this] var someField: Int) {}
我希望将someField
构造函数参数转换为private[this]
volatile字段。但是我收到了一个警告:
no valid targets for annotation on variable someField - it is discarded unused. You may specify targets with meta-annotations, e.g. @(volatile @scala.annotation.meta.field @param)
但是,如果我用private[this]
替换private
,一切都很好。
我使用Scala 2.11.6。
你能帮帮我吗?
答案 0 :(得分:1)
通过使用javap,您可以看到您的类没有名为someField的字段。原因是你没有使用它,似乎在私有[this]变量的情况下,如果不使用,scala会自动丢弃整个字段。
Welcome to Scala version 2.11.6 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_2
0).
Type in expressions to have them evaluated.
Type :help for more information.
scala> import scala.annotation.meta._
import scala.annotation.meta._
scala> class MyClass(@(volatile @field) private[this] var someField: Int) {}
<console>:10: warning: no valid targets for annotation on variable someField - i
t is discarded unused. You may specify targets with meta-annotations, e.g. @(vol
atile @scala.annotation.meta.field @param)
class MyClass(@(volatile @field) private[this] var someField: Int) {}
^
defined class MyClass
scala> :javap -verbose -private MyClass
Size 562 bytes
MD5 checksum 05ce62de304576552a958ee79ec4b2b7
Compiled from "<console>"
public class MyClass
minor version: 0
major version: 50
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Utf8 MyClass
#2 = Class #1 // MyClass
#3 = Utf8 java/lang/Object
#4 = Class #3 // java/lang/Object
#5 = Utf8 <console>
#6 = Utf8 <init>
#7 = Utf8 (I)V
#8 = Utf8 ()V
#9 = NameAndType #6:#8 // "<init>":()V
#10 = Methodref #4.#9 // java/lang/Object."<init>":()V
#11 = Utf8 this
#12 = Utf8 LMyClass;
#13 = Utf8 someField
#14 = Utf8 I
#15 = Utf8
#16 = Class #15 //
#17 = Utf8 $line4/$read
#18 = Class #17 // $line4/$read
#19 = Utf8
#20 = Utf8
#21 = Class #20 //
#22 = Utf8
#23 = Class #22 //
#24 = Utf8
#25 = Class #24 //
#26 = Utf8 MyClass
#27 = Utf8 Code
#28 = Utf8 LocalVariableTable
#29 = Utf8 LineNumberTable
#30 = Utf8 SourceFile
#31 = Utf8 InnerClasses
#32 = Utf8 Scala
{
public MyClass(int);
descriptor: (I)V
flags: ACC_PUBLIC
Code:
stack=1, locals=2, args_size=2
0: aload_0
1: invokespecial #10 // Method java/lang/Object."<init>
":()V
4: return
LocalVariableTable:
Start Length Slot Name Signature
0 5 0 this LMyClass;
0 5 1 someField I
LineNumberTable:
line 14: 0
}
SourceFile: "<console>"
InnerClasses:
public static #19= #16 of #18; //=class of class $line4/$read
public static #19= #21 of #16; //=class of class
public static #19= #23 of #21; //=class of class
public static #19= #25 of #23; //=class of class
public static #26= #2 of #25; //MyClass=class MyClass of class
Error: unknown attribute
Scala: length = 0x0
但是如果你在你的班级中使用那个变量,你会发现你有一个易变的字段:
Welcome to Scala version 2.11.6 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_2
0).
Type in expressions to have them evaluated.
Type :help for more information.
scala> import scala.annotation.meta._
import scala.annotation.meta._
scala> class MyClass(@(volatile @field) private[this] var someField: Int) {def u
seTheField=print(someField)}
<console>:10: warning: no valid targets for annotation on variable someField - i
t is discarded unused. You may specify targets with meta-annotations, e.g. @(vol
atile @scala.annotation.meta.field @param)
class MyClass(@(volatile @field) private[this] var someField: Int) {def u
seTheField=print(someField)}
^
defined class MyClass
scala> :javap -verbose -private MyClass
Size 854 bytes
MD5 checksum c7e8340b43d0416e81554b586d122a01
Compiled from "<console>"
public class MyClass
minor version: 0
major version: 50
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Utf8 MyClass
#2 = Class #1 // MyClass
#3 = Utf8 java/lang/Object
#4 = Class #3 // java/lang/Object
#5 = Utf8 <console>
#6 = Utf8 someField
#7 = Utf8 I
#8 = Utf8 useTheField
#9 = Utf8 ()V
#10 = Utf8 scala/Predef$
#11 = Class #10 // scala/Predef$
#12 = Utf8 MODULE$
#13 = Utf8 Lscala/Predef$;
#14 = NameAndType #12:#13 // MODULE$:Lscala/Predef$;
#15 = Fieldref #11.#14 // scala/Predef$.MODULE$:Lscala/Predef
$;
#16 = NameAndType #6:#7 // someField:I
#17 = Fieldref #2.#16 // MyClass.someField:I
#18 = Utf8 scala/runtime/BoxesRunTime
#19 = Class #18 // scala/runtime/BoxesRunTime
#20 = Utf8 boxToInteger
#21 = Utf8 (I)Ljava/lang/Integer;
#22 = NameAndType #20:#21 // boxToInteger:(I)Ljava/lang/Integer;
#23 = Methodref #19.#22 // scala/runtime/BoxesRunTime.boxToInt
eger:(I)Ljava/lang/Integer;
#24 = Utf8 print
#25 = Utf8 (Ljava/lang/Object;)V
#26 = NameAndType #24:#25 // print:(Ljava/lang/Object;)V
#27 = Methodref #11.#26 // scala/Predef$.print:(Ljava/lang/Obj
ect;)V
#28 = Utf8 this
#29 = Utf8 LMyClass;
#30 = Utf8 <init>
#31 = Utf8 (I)V
#32 = NameAndType #30:#9 // "<init>":()V
#33 = Methodref #4.#32 // java/lang/Object."<init>":()V
#34 = Utf8
#35 = Class #34 //
#36 = Utf8 $line4/$read
#37 = Class #36 // $line4/$read
#38 = Utf8
#39 = Utf8
#40 = Class #39 //
#41 = Utf8
#42 = Class #41 //
#43 = Utf8
#44 = Class #43 //
#45 = Utf8 MyClass
#46 = Utf8 Code
#47 = Utf8 LocalVariableTable
#48 = Utf8 LineNumberTable
#49 = Utf8 SourceFile
#50 = Utf8 InnerClasses
#51 = Utf8 Scala
{
private volatile int someField;
descriptor: I
flags: ACC_PRIVATE, ACC_VOLATILE
public void useTheField();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=2, locals=1, args_size=1
0: getstatic #15 // Field scala/Predef$.MODULE$:Lsc
ala/Predef$;
3: aload_0
4: getfield #17 // Field someField:I
7: invokestatic #23 // Method scala/runtime/BoxesRunTi
me.boxToInteger:(I)Ljava/lang/Integer;
10: invokevirtual #27 // Method scala/Predef$.print:(Lja
va/lang/Object;)V
13: return
LocalVariableTable:
Start Length Slot Name Signature
0 14 0 this LMyClass;
LineNumberTable:
line 10: 0
public MyClass(int);
descriptor: (I)V
flags: ACC_PUBLIC
Code:
stack=2, locals=2, args_size=2
0: aload_0
1: iload_1
2: putfield #17 // Field someField:I
5: aload_0
6: invokespecial #33 // Method java/lang/Object."<init>
":()V
9: return
LocalVariableTable:
Start Length Slot Name Signature
0 10 0 this LMyClass;
0 10 1 someField I
LineNumberTable:
line 10: 0
line 14: 5
}
SourceFile: "<console>"
InnerClasses:
public static #38= #35 of #37; //=class of class $line4/$read
public static #38= #40 of #35; //=class of class
public static #38= #42 of #40; //=class of class
public static #38= #44 of #42; //=class of class
public static #45= #2 of #44; //MyClass=class MyClass of class
Error: unknown attribute
Scala: length = 0x0
唯一的问题是你仍然会收到不使用volatile注释的警告,尽管它在编译的代码中肯定是正确使用的。因此,对于第二种情况,我认为显示警告是一个错误是安全的。
答案 1 :(得分:0)
这里没有专家,但以下似乎有效:
import annotation.meta.field
class Foo(init: Int) {
@volatile @field private[this] var x: Int = init
}
阅读(非常混乱)documentation,我感觉您的代码存在以下问题:@(volatile @field)
表示将volatile
注释复制到字段<{em>} someField
而不是默认目标构造函数参数。 但是:您没有指定someField
本身应该成为一个字段,因此没有目标。不确定这是否有意义。