你能在Java中获得变量的先前值吗?

时间:2009-03-04 15:08:26

标签: java variables

Say方式有一个变量(比如String Str),Str的值开始为“”然后当一些代码运行时,它被设置为“test”然后在代码中的其他地方再次更改为“测试仪”。现在在程序中我想知道Str的先前值是什么。这在Java中是否可行?

所以我说变量变了两次,你想知道Str在它第二次被改变之前是什么。因此在上面的示例中,Str的最新值将是“tester”,但我想在此之前找出Str是什么(假设您在将其更改为测试人员之前不知道它是什么)在这种情况下我想要成为能够发现Str是“测试”。

是否可以在Java中执行此操作?

14 个答案:

答案 0 :(得分:15)

不,这是不可能的,您必须在更改之前保存以前的值,以执行您要求的操作。

答案 1 :(得分:11)

不是语言的原生部分,不是。但是,当String发生变化时,您可以编写一个保存当前(前一个?)值的setter。

private String str;
private String prev;

setStr(String s)
{
    prev = str;
    str = s;
}

然后为prev写一个单独的getter。

当然,此解决方案依赖于您始终使用setter更改str的值。

另外,正如deworde指出的那样,如果您的程序不需要此信息,则不应修改程序以保存它。如果您需要用于调试的信息,可以在IDE的调试器中设置一个监视器。

答案 2 :(得分:5)

简单回答,不。

但是,您可以使用:

AOP

AOP框架,例如AspectJ可以截取变量的分配。

请参阅AspectJ pointcut reference

JavaBeans财产变更支持

您可以使用标准的JavaBean setter,getters来封装您的字段。然后,您可以在bean上注册侦听器以侦听属性更改,甚至否决该更改。

有关详细信息,请参阅JavaBean Spec

示例监听器:

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyVetoException;
import java.beans.VetoableChangeListener;

public class MyBeanListener implements PropertyChangeListener,
        VetoableChangeListener {

    @Override
    public void propertyChange(PropertyChangeEvent evt) {
        System.out.printf("Notifed of property changed event: %s => %s%n", evt
                .getOldValue(), evt.getNewValue());

    }

    @Override
    public void vetoableChange(PropertyChangeEvent evt)
            throws PropertyVetoException {
        System.out.printf("Notified of vetoable change event: %s => %s%n", evt
                .getOldValue(), evt.getNewValue());
    }
}

答案 3 :(得分:4)

如果你真的非常需要这个,你可以使用以下代码:

public class Main 
{
    public static void main(final String[] argv) 
    {
        SavedValue<Integer> i;

        i = new SavedValue<Integer>();
        i.set(7);
        System.out.println(i.get());
        System.out.println(i.getOld());
    }
}

class SavedValue<T>
{
    private T oldValue;
    private T value;

    void set(final T val)
    {
        oldValue = value;
        value    = val;
    }

    T get()
    {
        return (value);
    }

    T getOld()
    {
        return (oldValue);
    }
}

也许你可以解释为什么你想要旧的价值?如果我们知道为什么yoiu想要它,我相信我们可以给你更好的答案。

答案 4 :(得分:4)

你已经得到了两个简单的答案:

  • 不,Java本身不允许
  • 您可以使用setter并实现一种机制来保留旧值

但是到目前为止我还没有看到第三个:

应该可以在AspectJ中编写一个在赋值时触发的Aspect。所以它会有一个类似于setter的效果,没有实际的setter。如果您正在使用您不想要或不能更改的代码,这可能是一个选项。

请注意,虽然AspectJ不是Java,但结果是正常的字节代码,因此它应该与大多数环境兼容。

当然,不使用AspectJ,您可以使用CGLIB执行此操作。

答案 5 :(得分:2)

看起来你正在使用它进行调试,我是对的吗?

Visual Studio或任何体面的调试器应该允许您在每次设置时打印一个值的跟踪,只需在设置值的所有调用之前和之后放置一个“跟踪点”。

您只需更改正常断点的属性即可打印语句而不是暂停执行。 在VS2005中,这可以通过以下方式完成:

  • 打开断点窗口
  • 右键单击断点
  • 选择“Hit Hit ...”选项。
  • 选择“打印信息”并输入信息
  • 确保仍然选择“继续执行”。

这通常会在调试时显着降低程序速度,因此对于与时间相关的调试几乎没有用处;但它仍然允许我遵循变量的状态(ABCDFEGH ...)

当然,如果你想要暂停执行,只需转储正常的断点。

答案 6 :(得分:2)

您可以尝试使用堆栈数据结构。它将以正确的顺序保留所有先前的值。您可以实现自己的或使用java Collections one:

Deque<Integer> stack = new ArrayDeque<Integer>();

每次设置变量时,将其放入堆栈(通过setter或AOP,如其他答案中所述)。 这样,您就可以访问之前的值。

答案 7 :(得分:1)

确实,这是不可能的。您必须创建自己的String类,它具有某种内存来实现此目的。

答案 8 :(得分:1)

除了Stefan所说的,我还推荐一种包含所有历史价值的List结构。

如果要更改值,只需在列表末尾添加新值即可。如果要获取当前值,只需查看最后一个值即可。如果要查看以前的值,请从列表末尾开始。

答案 9 :(得分:0)

如果你能找到该程序的先前状态,就不会有任何垃圾收集,程序会很快耗尽内存。

对于特定变量,您可以使用LIFO堆栈。而不是你将推送到堆栈的任务。你可以偷看,而不是阅读变量。可以检查堆栈的内容以查找历史值。

另一种方法是使用instrumentation。这使您能够以足够的技巧和耐心重写字节代码,以执行您想要的任务。

也许你想稍微退一步看看你实际上想要实现的目标。

答案 10 :(得分:0)

我不知道想要这样做的原因,但我猜它是某种调试。

如果您正在使用eclipse,则可以设置在变量发生变化时触发的断点。这可能会实现我认为你想要达到的目标。

答案 11 :(得分:0)

事实上,这可以使用名为Historical Debugger的东西,它可以通过检测字节码来完成,以便记录对变量的任何赋值。

Gooogle Bil Lewis历史调试器就是一个例子。请注意,此软件的大部分都在您称之为“初始测试阶段”的阶段。

答案 12 :(得分:0)

你听说过Jive吗?它允许在调试中向后步进,因此这部分回答了您的问题请阅读此处:http://www.cse.buffalo.edu/jive/

答案 13 :(得分:0)

是!!更改值时,仅更改特定对象的值。见前:

 class Test{
int a=100; //original value 
 Test(int b){
    this.a=b;
 }
 Test(){
 }
void print(){
 System.out.println(a);
}
 public static void main(String args[]){
     Test t=new Test(9);
     Test t2=new Test();
     t.print();      //output: 9
     t2.print();     //output: 100 
 }
}