2009-09-22 152 views
2

我想知道是否有一種方法來指定一個方法在類方法之前被調用。我知道這樣的事情應該是可行的,因爲JUnit之前有(),我想要做的是類似的。Java註釋可以幫助我嗎?

這裏是想我做

class A { 

public void init(int a) { 
    System.out.println(a); 
} 

@magic(arg=1) 
public void foo() { 
    // 
} 

public static void main() { 
    A a = new A(); 
    a.foo(); 
} 
} 

//Output: 1 

基本上我想要一個註釋告訴編譯器或者FOO前的JVM調用的init()()

+0

對我來說,這聞起來像一個糟糕的設計決策。在另一種方法之前,不應該有一個方法必須被調用的限制。如果存在,設計和/或實施出現問題。 – 2009-09-22 13:09:57

+1

這對於更醜陋的黑客來說是件醜陋的事情。 – Mike 2009-09-22 13:15:21

+2

如果我是你,我會修復醜陋的黑客,讓你這樣做......但那只是我。 – 2009-09-22 13:16:26

回答

7

如果你有interface A你可以用這個接口的實例與Proxy和裏面的InvocationHandler你的invoke方法免費檢查方法是否被標註和執行取決於一些行動:

class Initalizer implements InvocationHandler { 
    private A delegate; 
    Initializer(A delegate) { 
     this.delegate = delegate; 
    } 

    public Object invoke(Object proxy, Method method, Object[] args) { 
     if (method.isAnnotationPresent(magic.class)) { 
      magic annotation = method.getAnnotation(magic.class); 
      delegate.init(magic.arg); 
     } 
     method.invoke(delegate, args); 
    } 
} 
A realA = ...; 
A obj = Proxy.newProxyInstance(A.class.getClassLoader(), new Class[] {A.class}, new Initializer(realA)); 

或者你也可以「之前」的AspectJ建議嘗試使用。這將是這樣的未來:

@Aspect 
public class Initializer { 
    @Before("@annotation(your.package.magic) && target(obj) && @annotation(annotation)") 
    private void initialize(A obj, magic annotation) {    
     a.init(annotation.arg); 
    } 
} 

我不知道該片段在工作,他們只是說明了想法。

+0

這個例子非常有幫助。謝謝。 – Mike 2009-09-22 16:50:54

+0

不客氣) – Rorick 2009-09-23 06:53:33

2

只是一個具體的例子在foo()的開始處調用Init()?

+1

。上面的例子簡化了我想要做的事 – Mike 2009-09-22 13:13:00

0

看一看AspectJ。它會幫助你做你正在問的東西。

2

AOP這是否符合所謂的切入點 AspectJ的可能有你需要的。

簡單地說,你會意見之前添加到您的FOO()方法,它會調用的init()

1

在java語言中沒有直接的方法來做到這一點。您在JUnit中看到的是框架,通過首先調用用@Before註釋的方法來決定如何運行這些方法。找到註釋的方法並運行它們非常容易,但這是調用者的責任。

你現在的問題是太簡單了,知道正確的方式來解決。 AspectJ通過操縱字節碼來滿足這種需求(當通過改變字節碼來調用foo()時,本質上調用init()方法來實現這一點),但我無法想象將它作爲一個問題的入侵。

如果你可以提出一個接口或一個包裝對象,這個類,你可以這樣做的。但我建議你發佈一個讓你陷入這種情況的醜陋黑客,首先在一個單獨的問題中,然後發佈你目前的黑客解決方案如何要求攔截方法調用,以及爲什麼會這樣,以及如果有更好的方法解決方法。這樣我們可以更好地解決潛在的需求。

0

我認爲這裏的問題是:

  1. 您有可以部分地建立對象的構造,但不能完全建立,因爲方式的類必須構建。 (我想不出一個例子副手的。)
  2. 所以你需要一個init()方法,將建設完成。
  3. 所以,你希望有一些種類的保證是init()將構造後立即被調用。

我的建議是使用一個工廠對象或方法。最簡單的方法是使構造函數保持私有,使用構造函數的參數或類似的東西添加construct()方法,然後讓construct()方法創建對象並調用init(),然後返回它。

3

你爲什麼要這麼做?你是否試圖避免讓一個具有許多參數的構造函數(使用setter然後調用init)還是​​避免使用許多構造函數都有類似的參數?如果是這種情況,您可以使用構建器模式。

public class Foo { 
int a, b, c, d, e; 
Foo(int a, int b, int c, int d, int e) { this.a=a; /*etc*/ } 
} 

public class FooBuilder { 
int a,b,c,d,e; 
FooBuilder A(int a) { this.a=a; return this;} 
FooBuilder B(int b) { this.b=b; return this;} 
//etc 
Foo create(){ return new Foo(a,b,c,d,e); 
} 

如果這不起作用,我會建議看看AOP。我將標記必須具有init()的方法的註釋(可能是@requires('init')等),並讓您的AOP框架插入正確的代碼。要小心多個init沒有副作用,或者在has_init_been_called狀態下做適當的同步。

相關問題