[英]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
之前發生...雖然我懷疑有更好的設計可用,但由於我們不知道你想要做什么,因此很難建議前進的方向。 例如,給你的超類構造函數采取一些參數可能是前進的方向 - 但我們現在還不能說。
如果您可以提供更具代表性的示例(包括您稍后提到的最后字段),我們可能會幫助您更多。
應首先調用超類構造函數 - 在它之前不能有任何語句,這是有道理的,因為在初始化之前必須實例化對象。
如果您無法通過重新設計應用程序來消除對此問題的需求,那么使用單獨的方法就可以解決此問題。
你提到了最終成員,所以我建議你要按特殊順序初始化它們......但如果我們看不到確切的問題,我們就無法給你公平的答案。
無論如何,我只想指出最終成員只能分配到兩個地方(據我所知)。
將值分配給最終成員的任何其他嘗試都將是編譯器錯誤。
我真的很想了解你的問題的起源和幫助。 你能提供更多細節嗎?
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.