Java 如何跟踪发生在对象上的一切?

Java 如何跟踪发生在对象上的一切?,java,Java,当集合(ArrayList)中的一个值被一段未知的代码(ArrayList实例保持不变)替换为null时,我遇到了一个错误。在几个事件之后,实际值将在同一索引处设置回集合中(0,并且值实例的id相同)。有几个自定义框架可能通过反射访问了集合,我找不到罪魁祸首 我尝试过用代理和不可修改的列表进行调试,但没有效果。我认为问题在于,ArrayList实例是由其中一个框架创建的,该框架可能会保留对列表的引用 我突然想到,如果有一个关于集合和价值发生的一切的日志,那就太好了。我的意思不仅仅是状态的改变,还

当集合(
ArrayList
)中的一个值被一段未知的代码(
ArrayList
实例保持不变)替换为
null
时,我遇到了一个错误。在几个事件之后,实际值将在同一索引处设置回集合中(
0
,并且值实例的id相同)。有几个自定义框架可能通过反射访问了集合,我找不到罪魁祸首

我尝试过用代理和不可修改的列表进行调试,但没有效果。我认为问题在于,
ArrayList
实例是由其中一个框架创建的,该框架可能会保留对列表的引用


我突然想到,如果有一个关于集合和价值发生的一切的日志,那就太好了。我的意思不仅仅是状态的改变,还包括从任何地方被引用。有没有办法查看对象的生活故事?

您可以覆盖ArrayList中最有趣的方法,如add、addAll、remove,如下所示:

public class MyList<T> extends ArrayList<T> {

// constructors

@Override
public boolean add(T value) {
    // log here
    super.add(value);
    // print stack trace, for example
}

// and so on
}
公共类MyList扩展了ArrayList{
//建设者
@凌驾
公共布尔加法(T值){
//在这里登录
超级增值;
//例如,打印堆栈跟踪
}
//等等
}

这不是一个干净的解决方案,但可能会有帮助

使用java.util.Collections.UnmodifiableList()将ArrayList更改为UnmodifiableList,然后检查哪里会出现异常。另一种方法是创建一个代理对象,代理每个方法调用并记录每个调用

java代理的示例—您需要代理的接口—在这个示例中,ArrayList的接口是List

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class ProxyTest {
    public static void main(String[] args) {

        final List<Object> list = new ArrayList<>();

        class MyInvocationHandler implements InvocationHandler {

            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println("Invoking method: " + method.getName() +", with params: "+Arrays.asList(args));

                return method.invoke(list, args);
            }
        }

        InvocationHandler handler = new MyInvocationHandler();
        List proxy = (List) Proxy.newProxyInstance(List.class.getClassLoader(), new Class[] { List.class }, handler);


        proxy.add("hello");
    }
}
import java.lang.reflect.InvocationHandler;
导入java.lang.reflect.Method;
导入java.lang.reflect.Proxy;
导入java.util.ArrayList;
导入java.util.array;
导入java.util.List;
公共类代理测试{
公共静态void main(字符串[]args){
最终列表=新的ArrayList();
类MyInvocationHandler实现InvocationHandler{
公共对象调用(对象代理、方法、对象[]args)抛出Throwable{
System.out.println(“调用方法:“+method.getName()+”,参数:“+Arrays.asList(args));
返回方法.invoke(列表,参数);
}
}
InvocationHandler=新的MyInvocationHandler();
List proxy=(List)proxy.newProxyInstance(List.class.getClassLoader(),新类[]{List.class},处理程序);
代理。添加(“你好”);
}
}

在代码最相关的部分设置断点怎么样…?@ΦXocę웃Пepeúpaツ 是的,这样做了,但仍然无法确定替换的时刻或执行替换的代码。那么,不要让框架接触列表的内容……框架是通过通常的获取者访问列表的,不是吗?@ΦXocę웃Пepeúpaツ, 不,框架正在通过反射访问值,我无法分离它们进行测试,因为代码无法运行。我尝试过代理,但从未收到任何调用
remove()
add()
iterator()
-只有
isEmpty()
。那么,可能整个ArrayList被另一个实例替换了吗?您可以在包含ArrayList的字段上设置断点,然后每次访问该字段时断点都将停止。不,我检查了列表和值的实例ID是否保持不变。因此只有一种可能性:它根本不会被反射更改,而是在“普通”代码中更改,可能是在“for循环”中更改你得到了意想不到的额外通行证。你尝试过什么样的代理?扩展ArrayList?如果是这样的话,用代理来解决这个问题是不好的。这对我没有帮助,因为
ArrayList
实例是由其中一个框架创建的。