1. 前言

1.1 起因

在使用Eclipse进行调试时,发现某个对象的下面只显示对象的逻辑内容而不显示属性。如下图所示,myCollection对象只显示逻辑内容而不显示这些内容保存在哪个属性中。
在这里插入图片描述

1.2 寻因

在查询相关资料后,发现是与其实现了某些容器类接口有关,相关资料如下:
Show Logical Structure 在 Eclipse 中的显示行为与类是否实现了 Collection<E>Map<K,V> 接口密切相关。Eclipse 调试器对于集合类(如 ListSetMap)有特殊的处理逻辑。

1.3 Show Logical StructureCollection<E> 的关系

  1. 集合类的特殊处理
    当一个类实现了 Collection<E> 接口(或其子接口,如 ListSet)或者实现了 Map<K,V> 接口,Eclipse 调试器会专门处理这些类,以便显示集合的内容,而不是对象的具体字段(属性)。Show Logical Structure 的目的是简化查看这些集合中的元素,而不是展示整个对象的结构。

  2. 逻辑结构显示规则

    • 对于实现 Collection<E> 接口的类Show Logical Structure 会显示集合中的元素,而不是类的属性。即使类还有其他属性,它们也可能被 Eclipse 忽略,显示的主要是集合的逻辑内容。
    • 对于实现 Map<K,V> 的类:同样的,Show Logical Structure 会聚焦于键值对的内容,而不是 Map 对象的其他属性或元数据。
  3. 普通类的处理
    对于没有实现 Collection<E>Map<K,V> 接口的普通类,Eclipse 不会做这种特殊处理。按下 Show Logical Structure 后,Eclipse 仍然会显示该类的所有字段(属性)的名称和值,不会将其内容作为集合结构来显示。

1.4 实现 Collection<E>Map<K,V> 会影响 Eclipse 显示:

当类实现了 Collection<E>Map<K,V> 时,调试器会:

  • 优先显示集合的元素,而不是类的字段名称。
  • 忽略非集合的字段,并直接展示集合内部的逻辑结构(如 List 的元素或 Map 的键值对)。

1.5 示例

假设有一个类 MyList,它继承了 ArrayList

import java.util.ArrayList;

public class MyList<E> extends ArrayList<E> {
    private String metadata;

    public MyList(String metadata) {
        this.metadata = metadata;
    }

    public String getMetadata() {
        return metadata;
    }
}

如果你调试一个 MyList 对象,并按下 Show Logical Structure 按钮,Eclipse 调试器会专注于显示 ArrayList 的元素,而不会展示 metadata 属性。即使 metadata 存在,调试面板中也会忽略它,只显示集合元素。

同样的道理,任何实现了 Collection<E> 接口的类,在调试时 Eclipse 都会默认展示集合的内容,而不显示其他属性。

1.6 如果不实现 Collection<E>

如果类没有实现 Collection<E>,即使它内部有 ListMap 类型的字段,按下 Show Logical Structure 时,Eclipse 仍然会显示类的所有字段及其名称。这时,调试器不会做集合类的特殊处理,依旧会展示属性名和值。

1.7 结论:

  • 实现 Collection<E>Map<K,V> 接口的类,在按下 Show Logical Structure 后,Eclipse 会专注于显示集合内部的元素,而忽略其他字段。
  • 如果不希望 Eclipse 在调试时显示某些字段,可以利用这一特性,通过继承集合类或实现集合接口来控制调试器的显示逻辑。

好的,下面是一个完整的示例,展示如何创建一个自定义集合类,继承自 Collection<Object>。在这个示例中,我们将实现基本的集合功能,并且当在 Eclipse 中按下 Show Logical Structure 时,将优先显示集合中的元素。

2 完整代码示例

2.1 创建 MyCollection

该类实现了 Collection<Object> 接口,并提供了必要的方法。

import java.util.Iterator;
import java.util.NoSuchElementException;

public class MyCollection implements Collection<Object> {
    private Object[] elements;
    private int size;
    private static final int INITIAL_CAPACITY = 10;

    public MyCollection() {
        elements = new Object[INITIAL_CAPACITY];  // 初始化数组
        size = 0;
    }

    @Override
    public boolean add(Object e) {
        if (size >= elements.length) {
            resize();  // 如果数组满了,扩展容量
        }
        elements[size++] = e;  // 添加元素
        return true;
    }

    private void resize() {
        Object[] newArray = new Object[elements.length * 2];
        System.arraycopy(elements, 0, newArray, 0, elements.length);
        elements = newArray;  // 更新数组
    }

    @Override
    public boolean remove(Object o) {
        for (int i = 0; i < size; i++) {
            if (elements[i].equals(o)) {
                System.arraycopy(elements, i + 1, elements, i, size - i - 1);
                elements[--size] = null;  // 清理最后一个元素
                return true;
            }
        }
        return false;
    }

    @Override
    public boolean isEmpty() {
        return size == 0;  // 判断是否为空
    }

    @Override
    public int size() {
        return size;  // 返回大小
    }

    @Override
    public Iterator<Object> iterator() {
        return new Iterator<Object>() {
            private int currentIndex = 0;

            @Override
            public boolean hasNext() {
                return currentIndex < size;  // 判断是否有下一个元素
            }

            @Override
            public Object next() {
                if (!hasNext()) {
                    throw new NoSuchElementException();  // 如果没有下一个元素,抛出异常
                }
                return elements[currentIndex++];  // 返回当前元素并递增索引
            }
        };
    }

    @Override
    public Object[] toArray() {
        Object[] array = new Object[size];
        System.arraycopy(elements, 0, array, 0, size);  // 返回当前数组的副本
        return array;
    }

    @Override
    public <T> T[] toArray(T[] a) {
        if (a.length < size) {
            return (T[]) toArray();  // 返回新数组
        }
        System.arraycopy(elements, 0, a, 0, size);  // 复制到传入的数组
        if (a.length > size) {
            a[size] = null;  // 清理多余元素
        }
        return a;
    }

    @Override
    public boolean contains(Object o) {
        for (int i = 0; i < size; i++) {
            if (elements[i].equals(o)) {
                return true;  // 找到元素返回 true
            }
        }
        return false;  // 未找到元素返回 false
    }

    @Override
    public boolean addAll(Collection<? extends Object> c) {
        boolean modified = false;
        for (Object e : c) {
            if (add(e)) {
                modified = true;  // 如果添加成功,标记为修改
            }
        }
        return modified;  // 返回是否有修改
    }

    @Override
    public boolean containsAll(Collection<?> c) {
        for (Object e : c) {
            if (!contains(e)) {
                return false;  // 如果有未包含的元素,返回 false
            }
        }
        return true;  // 所有元素均被包含
    }

    @Override
    public boolean removeAll(Collection<?> c) {
        boolean modified = false;
        for (Object e : c) {
            if (remove(e)) {
                modified = true;  // 如果移除成功,标记为修改
            }
        }
        return modified;  // 返回是否有修改
    }

    @Override
    public boolean retainAll(Collection<?> c) {
        boolean modified = false;
        for (int i = 0; i < size; i++) {
            if (!c.contains(elements[i])) {
                remove(elements[i]);  // 只保留包含的元素
                modified = true;  // 标记为修改
                i--;  // 调整索引
            }
        }
        return modified;  // 返回是否有修改
    }

    @Override
    public void clear() {
        for (int i = 0; i < size; i++) {
            elements[i] = null;  // 清理所有元素
        }
        size = 0;  // 重置大小
    }
    
    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder("[");
        for (int i = 0; i < size; i++) {
            sb.append(elements[i]);
            if (i < size - 1) {
                sb.append(", ");  // 添加逗号
            }
        }
        sb.append("]");
        return sb.toString();  // 返回字符串表示
    }
}
2.2 创建一个简单的 Main 类来测试

这个类将创建 MyCollection 实例,并添加一些元素。

public class Main {
    public static void main(String[] args) {
        // 创建 MyCollection 实例
        MyCollection myCollection = new MyCollection();

        // 添加元素到集合
        myCollection.add("Item 1");
        myCollection.add("Item 2");
        myCollection.add("Item 3");

        // 打印 MyCollection 对象
        System.out.println(myCollection);

        // 在此处设置断点,使用 Eclipse 调试功能中的 "Show Logical Structure" 查看 myCollection 的内容
    }
}

2.3 调试过程

  1. 设置断点:在 System.out.println(myCollection); 这行代码上设置一个断点。
  2. 运行调试:启动调试模式。
  3. 按下 Show Logical Structure
    • 在调试时,展开 myCollection 对象,你应该看到它的元素(“Item 1”、“Item 2”、“Item 3”)被展示,而 MyCollection 的其他属性将不会出现在显示中。

2.4 输出示例

  • 在控制台输出
    [Item 1, Item 2, Item 3]
    
  • 在调试面板中(按下 Show Logical Structure 后)
    Item 1
    Item 2
    Item 3
    

2.5 总结

在这个示例中,由于 MyCollection 实现了 Collection<Object> 接口,因此在调试时,Eclipse 会优先显示集合中的元素,而不显示其他属性。这样可以有效地控制调试输出,专注于集合的逻辑内容。

点赞(0) 打赏

评论列表 共有 0 条评论

暂无评论

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部