在没有exit命令的情况下输入了exit()方法



我有Processing 3代码,它显示出一些奇怪的行为。我定义了一个void exit()方法,它在没有用户实际告诉代码退出的情况下随机执行。方法如下:

void exit()
{
println("clearing buffer and closing file");
if (output != null) {
print("output is not null");
try {
output.close();
} 
catch (IOException e) {
println("Error while closing the writer");
}
}
super.exit();
}

正如您所看到的,它所做的唯一一件事就是尝试关闭一个名为output的缓冲写入程序。冲洗这位作家并不挑剔,所以现在我只是把它从我的草图中删除。但从长远来看,我很好奇这是怎么发生的。在我的代码中,没有其他地方显式调用exit方法。IE,代码无法决定退出。只有当用户使用X.关闭问题时

注意:我无法上传整个代码,这个方法也被附加了,因为它太长了。我想也许更好的表达方式是:

"嗨,我是一个对退出方法一无所知的傻瓜。有没有可能在没有我明确调用或按下退出按钮的情况下,以某种方式调用这个方法?">

将其添加到exit()方法的开头。

new Exception().printStackTrace();

由此产生的stacktrace应该可以让您弄清楚是什么在调用exit()方法。

或者,如果不能调整代码,可以使用调试器运行应用程序,并在exit()方法的开头设置断点。


要回答你关于这是否可能的问题,答案取决于你所说的"没有我明确打电话"是什么意思。有多种方法可以调用一个方法,其中一些方法相当模糊;例如

  • 可以使用反射从声明类中获取exit方法的Method对象,然后对其调用invoke(...)
  • 您可以通过JNI或JNAAPI从本机代码中调用Java方法
  • 您可以生成包含exit()调用的Java源代码,对其进行编译、加载并运行
  • 您可以使用BCEL或类似方法将exit()调用插入到"无辜"方法中

还有。。。

  • 如果JVM上附加了调试代理,则调试器可以在JVM中的某个线程上调用exit()

简而言之,您的问题的答案是肯定的。

您的方法可以由同一类加载器中的任何类或层次结构中的任何其他类使用反射来找到和动态调用。

此外,它具有默认访问权限。因此,它可以由同一包中的任何类静态调用。

+1对于@Andres,反射是一种可能性。

您是否尝试过在方法上使用断点并查看线程的堆栈跟踪?

就我个人而言,我不使用断点(只是我的风格),会尝试以编程方式查看线程。也许下面的一些代码可以帮助您查看线程并了解发生了什么:

public class ThreadUtil {
/** Blocked constructor **/
private ThreadUtil() {
}
/**
* Get the stackstrace of the current {@link Thread}.
* The stacktrace will be returned in the form of a string.
*/
public static String getStackTrace() {
return getStackTrace(Thread.currentThread());
}
/**
* Get the stackstrace of a {@link Thread}.
* The stacktrace will be returned in the form of a string.
*/
public static String getStackTrace(Thread thread) {
StringBuilder sb = new StringBuilder();
StackTraceElement[] currThreadStackTraceElementList = thread.getStackTrace();
appendStackTrace(sb, currThreadStackTraceElementList);
return sb.toString();
}
public static String getAllStackTraces() {
StringBuilder sb = new StringBuilder();
Map<Thread, StackTraceElement[]> threadList = Thread.getAllStackTraces();
for (StackTraceElement[] currThreadStackTraceElementList : threadList.values()) {
appendStackTrace(sb, currThreadStackTraceElementList);
}
return sb.toString();
}
private static void appendStackTrace(StringBuilder sb,
StackTraceElement[] currThreadStackTraceElementList) {
sb.append("Thread stack trace: n");
for (StackTraceElement currThreadStackTraceElement : currThreadStackTraceElementList) {
sb.append("t" + currThreadStackTraceElement + "n");
}
sb.append("n");
}
}

这是一个处理特定的东西。

void exit()是PApplet.java 中已经通过处理定义的方法

如参考文献所述:

exit()不会立即终止,而是会导致草图draw()完成后退出(或调用setup()后退出在setup()函数期间)。

对于Java程序员来说,这与System.exit()不同。此外,不应使用System.exit(),因为正在关闭应用程序draw()运行时可能会导致崩溃(尤其是P3D)。

exit()预计会使用类似的东西:

void draw() {
line(mouseX, mouseY, 50, 50);
}
void mousePressed() {
exit(); 
}

它在PApplet.java中的一些地方被调用,特别是在handleKeyEvent中,以在按下ESC或按下⌘w时关闭草图。

只需将您的方法重命名为exit()以外的东西

最新更新