为什么我的对象已被IntelliJ IDEA的调试器无声地更改?

时间:2019-04-28 10:02:56

标签: java debugging intellij-idea

我正在调试(Shift + F9)JDK8 API的offer(E e)的方法java.util.concurrent.ConcurrentLinkedQueue

我发现IntelliJ IDEA将在调试过程中无声地更改此队列的字段head

但是运行模式(Shift + F10)不会更改字段,为什么?

offer(E e)中没有代码更改此字段,这让我感到困惑。

然后,我尝试了另一个IDE(Eclipse Mars.1版本(4.5.1)),它没有这样的问题。

我的测试有一些结果:

  • 运行模式(Shift + F10)
head: 1159190947 
head: 1159190947 
head: 1159190947 
head: 1159190947 
  • 调试模式(跳过:F8)
head: 1989972246 
head: 1791930789 
head: 1791930789 
head: 1791930789 
  • 调试模式(恢复程序:F9)
head: 1989972246 
head: 1989972246 
head: 1791930789 
head: 1791930789 

版本信息:
IntelliJ IDEA 2018.1(最终版)
Build#IU-181.4203.550,建于2018年3月27日
JRE:1.8.0_162-b12 amd64
JVM:Oracle Corporation的Java HotSpot(TM)64位服务器VM
Windows 10 10.0

IntelliJ IDEA 2018.2.3(社区版) IntelliJ IDEA 2019.1(最终版)遇到相同的问题。

import java.lang.reflect.Field;
import java.util.concurrent.ConcurrentLinkedQueue;

public class ConcurrentLinkedQueueTest {

    public static void main(String[] args) {
        ConcurrentLinkedQueue<String> queue = new ConcurrentLinkedQueue<>();
        print(queue);
        queue.offer("aaa");
        print(queue);
        queue.offer("bbb");
        print(queue);
        queue.offer("ccc");
        print(queue);
    }

    /**
     * 打印并发队列head属性的identityHashCode
     * @param queue
     */
    private static void print(ConcurrentLinkedQueue queue) {
        Field field = null;
        boolean isAccessible = false;
        try {
            field = ConcurrentLinkedQueue.class.getDeclaredField("head");
            isAccessible = field.isAccessible();
            if (!isAccessible) {
                field.setAccessible(true);
            }
            System.out.println("head: " + System.identityHashCode(field.get(queue)));
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            field.setAccessible(isAccessible);
        }
    }
}

1 个答案:

答案 0 :(得分:5)

默认情况下,IntelliJ IDEA在对象上调用toString()方法以在“监视”视图中获取其表示。在ConcurrentLinkedQueue中,toString()方法遍历集合,后者可以通过head方法中的updateHead()调用(可能在其他方法中)来更新first()字段。地方,我还没有研究整个实施过程。

如果转到首选项|构建,执行,部署|调试器数据视图Java,然后关闭“启用toString()对象视图”,您就不再应该观察到此行为。