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

Java 检查实例方法是否从构造函数调用,java,debugging,assertions,Java,Debugging,Assertions,我想从非final类的实例方法检查该类的构造函数和初始值设定项以及特定实例的子类链是否已经完成 在下面的示例中,我有一个类Abstract,它可以用来实现一个接口,该接口允许添加侦听器(为了简单起见,这里只是可运行的实例),并提供一个方法signalEvent(),该方法调用所有连接的侦听器 abstract class Abstract { protected final void signalEvent() { // Check that constructs hav

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

在下面的示例中,我有一个类
Abstract
,它可以用来实现一个接口,该接口允许添加侦听器(为了简单起见,这里只是
可运行的
实例),并提供一个方法
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
语句或类似语句)


是否可以检查实例方法是否直接或间接地从当前实例的子类构造函数或初始值设定项调用,或者,是否可以检查实例的所有构造函数是否都已完成?

简而言之,没有优雅的Java机制允许您这样做,但是你可以考虑使用工厂模式。与直接使用
new
关键字创建实例不同,您可以创建一个工厂类,负责创建实际实例,并调用一个附加的“post-create”方法,让实例知道它已完全创建

如果您使用的是一些依赖项注入,比如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;
    }
}
interface PostConstruct{//类需要实现该功能
无效后构造();
}
公共类InstanceFactory{
公共T创建(类类别、对象…参数){
T instance=//使用反射创建
instance.postConstruct();
返回实例;
}
}

问题的解决方案,以查看是否正在从构造函数调用方法或代码。下面的代码将分别打印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;
    }
公共类TestClass扩展TestAbstract{
公共TestClass()引发异常{
子方法();
}
public void submethod()引发异常{
System.out.println(isInConstructor());
}
公共静态void main(字符串[]args)引发异常{
System.out.println(新的TestClass().isInConstructor());
}
}
公共类测试摘要{
公共布尔值isInConstructor()引发异常{
StackTraceElement[]元素=Thread.currentThread().getStackTrace();
用于(StackTraceElement元素:元素){
if(element.getMethodName()等于(“”)&&
TestAbstract.class.isAssignableFrom(class.forName(element.getClassName())){
返回true;
}
}
返回false;
}

}

您为什么不能在超级构造函数中设置布尔设置并在signalEvent中检查是否正确?如果我理解正确,您的要求和问题不匹配。。。即使在所有构造函数返回后调用了
signalEvent()
,也同样有可能没有添加侦听器。你是怎么处理这个案子的?依我看,检查是否添加了侦听器要简单得多。@D357在子类构造函数运行之前设置布尔值。因此,我无法从子类构造函数中检测到对
signalEvent()
的调用。@Codebender您是对的。在没有附加侦听器的情况下,构造函数运行后可能会错过事件。不同之处在于,如果要附加侦听器,在我们的用例中,几乎总是在构建实例后立即进行。OTOH,在我们的项目中,有一些“有效”的情况,没有任何监听器被附加到实例上,这很好。。。如果您从任何构造函数(不一定是实例对象的构造函数)调用该方法,这将返回true。非常正确,没有检查太多,因为我根本不想鼓励这样做。。现在我花了很多时间在它上面:)事实上,仔细想想,从技术上讲,有一种方法可以实现您的要求,那就是使用
Thread.currentThread().getStackTrace()
检查堆栈跟踪内容,但出于性能原因,我不建议这样做,最重要的是,这样会使您的代码不可读。