想想Java构造函数

时间:2011-04-10 09:09:46

标签: java

在这个例子中:

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方法可能是唯一的方法吗?

3 个答案:

答案 0 :(得分:9)

即使在第二个示例中,您也需要B.init()调用super.init(),否则init1的逻辑将无法执行

我会尝试来使用这种init方法 - 通常在构造函数中调用虚方法是一个非常糟糕的主意。你还没有真正解释为什么你需要init2才能在init1之前发生...尽管......我怀疑有更好的设计可用,但很难建议前进的方向我们不知道你要做什么。例如,给你的超类构造函数取一些参数可能就是前进的方向 - 但我们现在还不能说。

如果您能提供更具代表性的示例(包括您稍后提及的最后字段),我们可能会为您提供更多帮助。

答案 1 :(得分:2)

首先应该调用超类构造函数 - 在它之前不能有任何语句,这是有道理的,因为在初始化之前必须实例化对象。

如果您无法通过重新设计应用程序来消除对此问题的需求,那么使用单独的方法可以解决此问题。

答案 2 :(得分:2)

您提到了最终成员,所以我建议您要按特殊顺序初始化它们... 但如果我们看不到确切的问题,我们就无法给你答案。

无论如何,我只想指出最终成员只能分配到两个地方(据我所知)。

  1. 在您声明它们的地方,
  2. 或在构造函数上下文中。
  3. 任何其他尝试将值分配给最终成员都将是编译器错误。

    我真的很想了解你的问题的起源和帮助。你能提供更多细节吗?

相关问题