检查是从构造函数调用实例方法

时间:2015-07-06 14:31:07

标签: java debugging assertions

我想从非final类的实例方法中检查该类的构造函数和初始值设定项及其特定实例的子类链是否已经完成。

在下面的示例中,我有一个类Abstract,可以用来实现一个允许添加侦听器的接口(为简单起见,这里只是Runnable个实例)提供了一个调用所有附加侦听器的方法signalEvent()

abstract class Abstract {
    protected final void signalEvent() {
        // Check that constructs have run and call listeners.
    }

    public final void addListener(Runnable runnable) {
        ...
    }
}

class Concrete extends Abstract {
    Concrete() {
        // Should not call signalEvent() here.
    }

    void somethingHappened() {
        // May call signalEvent() here.
    }
}

现在可以从子类构造函数中调用signalEvent(),但是那时候没有办法添加一个监听器,事件就会丢失。在我们的代码库中,偶尔会有人添加这样的调用,我希望能够尽早捕获这些调用(使用assert语句或类似的语句)。

是否可以检查实例方法是直接还是间接地从当前实例的子类构造函数或初始化程序调用,或者是否可以检查实例的所有构造函数是否都已完成? / p>

2 个答案:

答案 0 :(得分:1)

简而言之,没有优雅的Java机制允许您这样做,但您可以考虑使用工厂模式。您可以创建一个工厂类,而不是直接使用new关键字创建实例,该工作类负责创建实际实例并调用其他"后创建"方法,让实例知道它已被完全创建。

如果您正在使用像spring这样的依赖注入,那么您就可以开箱即用,但如果没有,解决方案可能看起来像这样:

interface PostConstruct { // the classes need to implement that
    void postConstruct();
}

public class InstanceFactory {
    public <T extends PostConstruct> T create(Class<T> clazz, Object... params) {
        T instance = //create using reflection
        instance.postConstruct();
        return instance;
    }
}

答案 1 :(得分:1)

解决问题的方法,以查看是否从构造函数中调用了方法或代码。下面的代码将分别打印为true和false,但速度很慢而且根本不相同。

我仍然认为这不是解决上述问题的正确方法。正如Codbender所说,最好检查一下是否添加了一个监听器,或设置一个更快的状态变量

编辑 - 修复了Codebender提到的问题,并确保在堆栈跟踪中检查是否被深深地调用了几个方法

public class TestClass extends TestAbstract {

    public TestClass() throws Exception {
       submethod();
    }

    public void submethod() throws Exception {
        System.out.println(isInConstructor());
    }

    public static void main(String[] args) throws Exception {
        System.out.println(new TestClass().isInConstructor());
    }

}

public class TestAbstract {

    public boolean isInConstructor() throws Exception {
        StackTraceElement[] elements = Thread.currentThread().getStackTrace();
        for (StackTraceElement element : elements) {
            if (element.getMethodName().equals("<init>") &&
                TestAbstract.class.isAssignableFrom(Class.forName(element.getClassName()))) {
                return true;
            }
        }
        return false;
    }

}