Say方式有一个变量(比如String Str),Str的值开始为“”然后当一些代码运行时,它被设置为“test”然后在代码中的其他地方再次更改为“测试仪”。现在在程序中我想知道Str的先前值是什么。这在Java中是否可行?
所以我说变量变了两次,你想知道Str在它第二次被改变之前是什么。因此在上面的示例中,Str的最新值将是“tester”,但我想在此之前找出Str是什么(假设您在将其更改为测试人员之前不知道它是什么)在这种情况下我想要成为能够发现Str是“测试”。
是否可以在Java中执行此操作?
答案 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框架,例如AspectJ可以截取变量的分配。
您可以使用标准的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)
你已经得到了两个简单的答案:
但是到目前为止我还没有看到第三个:
应该可以在AspectJ中编写一个在赋值时触发的Aspect。所以它会有一个类似于setter的效果,没有实际的setter。如果您正在使用您不想要或不能更改的代码,这可能是一个选项。
请注意,虽然AspectJ不是Java,但结果是正常的字节代码,因此它应该与大多数环境兼容。
当然,不使用AspectJ,您可以使用CGLIB执行此操作。
答案 5 :(得分:2)
看起来你正在使用它进行调试,我是对的吗?
Visual Studio或任何体面的调试器应该允许您在每次设置时打印一个值的跟踪,只需在设置值的所有调用之前和之后放置一个“跟踪点”。
您只需更改正常断点的属性即可打印语句而不是暂停执行。 在VS2005中,这可以通过以下方式完成:
这通常会在调试时显着降低程序速度,因此对于与时间相关的调试几乎没有用处;但它仍然允许我遵循变量的状态(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
}
}