1. 前言
1.1 起因
在使用Eclipse进行调试时,发现某个对象的下面只显示对象的逻辑内容而不显示属性。如下图所示,myCollection对象只显示逻辑内容而不显示这些内容保存在哪个属性中。
1.2 寻因
在查询相关资料后,发现是与其实现了某些容器类接口有关,相关资料如下:
Show Logical Structure
在 Eclipse 中的显示行为与类是否实现了 Collection<E>
或 Map<K,V>
接口密切相关。Eclipse 调试器对于集合类(如 List
、Set
、Map
)有特殊的处理逻辑。
1.3 Show Logical Structure
与 Collection<E>
的关系
-
集合类的特殊处理 :
当一个类实现了
Collection<E>
接口(或其子接口,如List
、Set
)或者实现了Map<K,V>
接口,Eclipse 调试器会专门处理这些类,以便显示集合的内容,而不是对象的具体字段(属性)。Show Logical Structure
的目的是简化查看这些集合中的元素,而不是展示整个对象的结构。 -
逻辑结构显示规则:
- 对于实现
Collection<E>
接口的类 :Show Logical Structure
会显示集合中的元素,而不是类的属性。即使类还有其他属性,它们也可能被 Eclipse 忽略,显示的主要是集合的逻辑内容。 - 对于实现
Map<K,V>
的类 :同样的,Show Logical Structure
会聚焦于键值对的内容,而不是Map
对象的其他属性或元数据。
- 对于实现
-
普通类的处理 :
对于没有实现
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
:
java
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>
,即使它内部有 List
或 Map
类型的字段,按下 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>
接口,并提供了必要的方法。
java
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
实例,并添加一些元素。
java
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 调试过程
- 设置断点 :在
System.out.println(myCollection);
这行代码上设置一个断点。 - 运行调试:启动调试模式。
- 按下
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 会优先显示集合中的元素,而不显示其他属性。这样可以有效地控制调试输出,专注于集合的逻辑内容。