當您將註釋放置在變量上時,它將成爲該變量的靜態屬性,而不是您可以通過該變量到達的對象的靜態屬性。考慮:
public class A1 extends myA{
@Test("all")
private B b1=new B();
@Test("none")
private B b2=b1;
//....
public void interact(){
// this
b2.doSomethingBasedOnMyAnnotation();
// is exactly the same as
b1.doSomethingBasedOnMyAnnotation();
}
}
甚至無法假定存在一個帶註釋的變量。那麼
new B().doSomethingBasedOnMyAnnotation()
?
由於字段在編譯時被解析,因此無論如何都不會在所需的操作中進行抽象。如果您知道要調用b2.doSomethingBasedOnMyAnnotation();
,則您已知道自己正在使用哪個字段,並且將b2
的註釋值作爲參數提供給調用的方法沒有任何問題,而不是期望接收器神奇地發現。例如。
public class B{
public void doSomething(String arg){
}
}
public class A1 extends myA{
@Test("all")
private B b1;
@Test("none")
private B b2;
//....
public void interact(){
b1.doSomething(get("b1"));
b2.doSomething(get("b2"));
}
static String get(String fieldName) {
try {
return A1.class.getDeclaredField(fieldName)
.getAnnotation(Test.class).value();
} catch(NoSuchFieldException ex) {
throw new IllegalStateException(ex);
}
}
}
雖然我們可以不愉快工作的反思:
public class A1 extends myA{
static final String TEST_B1="all";
@Test(TEST_B1)
private B b1;
static final String TEST_B2="none";
@Test(TEST_B2)
private B b2;
static final String TEST_B3="none";
@Test(TEST_B3)
private B b3;
//....
public void interact(){
b1.doSomething(TEST_B1);
b2.doSomething(TEST_B2);
}
}
如果你想確保調用者不能被意外傳遞錯誤的參數,使用封裝來代替:
public final class EncapsulatedB {
final String testValue;
B b;
EncapsulatedB(String value) {
this(value, null);
}
EncapsulatedB(String value, B initialB) {
testValue=value;
b=initialB;
}
public B getB() {
return b;
}
public void setB(B b) {
this.b = b;
}
public void doSomething() {
b.doSomething(testValue);
}
}
public class A1 extends myA{
private final EncapsulatedB b1=new EncapsulatedB("all");
private final EncapsulatedB b2=new EncapsulatedB("none");
private final EncapsulatedB b3=new EncapsulatedB("none");
//....
public void interact(){
b1.doSomething();
b2.doSomething();
}
}