7

我想知道是否有任何方法可以在程序运行时观察变量值的变化。当然不使用调试器我想以编程方式进行。例如:

class A
{
   public static int valueToBeWatched;
}

所以在运行时,如果在我的项目中任何类的任何方法中修改了这个值MyValueChangeListner事件应该被调用。

4

4 回答 4

12

你不能。Java 本身没有内置监视修改钩子。显然,您可以进行轮询。但那样它就不会是“活的”。

AspectJ可能允许这样的想法,但我不确定它是否适用于原始变量,或者仅当您使用 getter 和 setter 时。

干净的Java方式是制作变量private并使用getter和setter。

private valueToBeWatched;

public void setValue(int newval) {
  valueToBeWatched = newval;
  notifyWatchers();
}

public int getValue() {
  return valueToBeWatched;
}

static附带说明一下,尽可能避免。特别是public但不是final

于 2012-09-12T11:00:04.883 回答
9

您需要将类型替换为int一个类,该类将在值更改时调用您的侦听器。您可能希望在实际未更改时忽略设置该值。

例如

 private int value;
 private final MyValueChangeListener listener;

 public void setValue(int value) {
    if(this.value == value) return;
    listener.changed(this, this.value, value);
    this.value = value;
 }

您可以使用字节码注入来执行此替换,但更改原始代码要简单得多。

另一种方法是监视值以定期查找更改。除非值变化非常缓慢,否则您可能看不到所有变化。您可以使用 Debugger API 来执行此操作,但它并不简单,除非您已经熟悉该 API,否则我不建议您使用它。

Java 调试器 API 链接

http://java.sun.com/javase/technologies/core/toolsapis/jpda/

http://docs.oracle.com/javase/6/docs/technotes/guides/jpda/

http://docs.oracle.com/javase/6/docs/jdk/api/jpda/jdi/

于 2012-09-12T10:59:33.977 回答
4

如果您可以使用 Oracle 的最新 Java SE JDK,那么我建议使用javafx.beans.propertyjavafx.beans.value API。

这是一些基本代码:

import javafx.beans.property.DoubleProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;

public class ObservableValues
{        

    public static void main(String[] args) 
    {
        DoubleProperty dp = new SimpleDoubleProperty(9);
        dp.addListener( new DoubleChangeListener() );
        dp.setValue(3);
        dp.setValue(6);
    }

    static class DoubleChangeListener implements ChangeListener<Number>
    {
        @Override
        public void changed(ObservableValue<? extends Number> ov, Number oldValue, Number newValue) 
        {
            System.out.println("the value has changed from " + oldValue + " to " + newValue);
        }
    }

}

这是输出:

该值已从 9.0 更改为 3.0

该值已从 3.0 更改为 6.0

于 2012-09-12T14:16:18.187 回答
1

如前所述,这个问题可以通过编写一个代理来解决所提供的字段的变化(参见fieldWatch)。代理必须使用与 C 调用兼容的语言进行编译,并在 VM 启动时通过-agentpath:<path-to-agent>=<options>开关调用。

更高级别的选项是使用JPDA /JDI附加到正在运行的进程,它将上述调用包装在 (Java) ModificationWatchpointEvent中。

于 2012-09-12T11:13:21.370 回答