簡體   English   中英

想想Java構造函數

[英]Think about Java constructor

在這個例子中:

class A {
    public A() {
        // pre-init1
        // post-init1
    }
}

class B extends A {
    public B() {
        super();
        // init2
    }
}

我想在init1之前讓init2,cuz super()必須在最開始發生,所以唯一的方法是添加另一個init方法:

class A {
    public A() {
        init();
    }

    protected void init() {
        // pre-init1
        // post-init1
    }
}

class B extends A {
    public B() {
        super();
    }

    protected void init() {
        // init2
        super.init();
    }
}

我可以擺脫init()方法嗎?

或者,我必須使最后的字段不是最終的。 或者,是否有任何方法讓A在init2之后執行post-init1,但不引入init()方法?

編輯

來自練習的代碼,我認為我需要這個特殊的init()用於特殊情況,

這是Spring JUnit測試的基礎支持類,由於某些原因我無法使用Spring-Test的SpringJUnit4Runner,所以我創建了自己的,

// wire the bean on demand.
public static <T> T selfWire(T bean) {
    if (bean == null)
        throw new NullPointerException("bean");

    ApplicationContext context = buildAnnotationDescribedContext(bean.getClass());
    AutowireCapableBeanFactory beanFactory = context.getAutowireCapableBeanFactory();
    beanFactory.autowireBean(bean);

    if (bean instanceof ApplicationContextAware) {
        ((ApplicationContextAware) bean).setApplicationContext(context);
    }
    if (bean instanceof InitializingBean) {
        try {
            ((InitializingBean) bean).afterPropertiesSet();
        } catch (RuntimeException e) {
            throw e;
        } catch (Exception e) {
            throw new RuntimeException("Failed to initialize bean", e);
        }
    }

    return bean;
}

@Import(TestContext.class)
public abstract class WiredTestCase 
        extends Assert
        implements InitializingBean {

    // ...

    public WiredTestCase() {
        init();
        ApplicationContextBuilder.selfWire(this);
        logger.debug("WiredTestCase wired");
    }

    protected void init() {
    }

    @Overrdie
    public void afterPropertiesSet() {
    }

}

@Import({ TestDaoConfig.class })
public class WiredDaoTestCase
        extends WiredTestCase {

    public WiredDaoTestCase() {
        // init... moved to init()
    }

    protected void init() {
        // Collect entity classes from @Using annotation
        // and config the session factory.
    }

}

@Using(IcsfIdentityUnit.class)
@ImportSamples(R_ACLSamples.class)
public class R_AuthorityTest
        extends WiredDaoTestCase {

    @Inject
    R_Authority authority;

    @Inject
    ScannedResourceRegistry registry;

    @Overrdie
    public void afterPropertiesSet() {
        // Do a lot of reflection discoveries.
        // ...
        super.afterPropertiesSet();
    }

    @Test
    public void testXxx() { ... }

    // ...
}

該代碼是很長,但這個想法很簡單,在R_AuthorityTest有被注入DAO豆,這取決於SessionFactory ,會話工廠在配置WiredDaoTestCase這是基類的R_AuthorityTest 盡管有最終字段,但我必須在WiredTestCase()之前初始化會話工廠。 我無法在靜態構造函數中初始化它們,因為我在this.getClass()上的注釋中動態構建了持久性單元。 所以,就個人而言,我認為有時候在超級構造函數之前做一些pre-init是合理的,在這種情況下,init方法可能是唯一的方法嗎?

即使在第二個例子中,你需要做B.init()調用super.init()否則的邏輯init1不會在所有執行。

我會盡量使用這種init方法 - 通常在構造函數中調用虛方法是一個非常糟糕的主意。 你還沒有真正解釋為什么你需要init2才能在init1之前發生...雖然我懷疑有更好的設計可用,但由於我們不知道你想要做什么,因此很難建議前進的方向。 例如,給你的超類構造函數采取一些參數可能是前進的方向 - 但我們現在還不能說。

如果您可以提供更具代表性的示例(包括您稍后提到的最后字段),我們可能會幫助您更多。

應首先調用超類構造函數 - 在它之前不能有任何語句,這是有道理的,因為在初始化之前必須實例化對象。

如果您無法通過重新設計應用程序來消除對此問題的需求,那么使用單獨的方法就可以解決此問題。

你提到了最終成員,所以我建議你要按特殊順序初始化它們......但如果我們看不到確切的問題,我們就無法給你公平的答案。

無論如何,我只想指出最終成員只能分配到兩個地方(據我所知)。

  1. 在你宣布他們的地方,
  2. 或者在構造函數的上下文中。

將值分配給最終成員的任何其他嘗試都將是編譯器錯誤。

我真的很想了解你的問題的起源和幫助。 你能提供更多細節嗎?

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM