在这个例子中:
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 bean,这取决于SessionFactory
,会话工厂在WiredDaoTestCase
中配置这是R_AuthorityTest
的基类。尽管有最终字段,但我必须在WiredTestCase()之前初始化会话工厂。我无法在静态构造函数中初始化它们,因为我在this.getClass()
上的注释中动态构建了持久性单元。所以,就个人而言,我认为有时候在超级构造函数之前做一些pre-init是合理的,在这种情况下,init方法可能是唯一的方法吗?
答案 0 :(得分:9)
即使在第二个示例中,您也需要B.init()
调用super.init()
,否则init1
的逻辑将无法执行
我会尝试不来使用这种init
方法 - 通常在构造函数中调用虚方法是一个非常糟糕的主意。你还没有真正解释为什么你需要init2
才能在init1
之前发生...尽管......我怀疑有更好的设计可用,但很难建议前进的方向我们不知道你要做什么。例如,给你的超类构造函数取一些参数可能就是前进的方向 - 但我们现在还不能说。
如果您能提供更具代表性的示例(包括您稍后提及的最后字段),我们可能会为您提供更多帮助。
答案 1 :(得分:2)
首先应该调用超类构造函数 - 在它之前不能有任何语句,这是有道理的,因为在初始化之前必须实例化对象。
如果您无法通过重新设计应用程序来消除对此问题的需求,那么使用单独的方法可以解决此问题。
答案 2 :(得分:2)
您提到了最终成员,所以我建议您要按特殊顺序初始化它们... 但如果我们看不到确切的问题,我们就无法给你答案。
无论如何,我只想指出最终成员只能分配到两个地方(据我所知)。
任何其他尝试将值分配给最终成员都将是编译器错误。
我真的很想了解你的问题的起源和帮助。你能提供更多细节吗?