- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我修改了对象转储方法以避免循环引用导致 StackOverflow 错误。这就是我最终的结果:
//returns all fields of the given object in a string
public static String dumpFields(Object o, int callCount, ArrayList excludeList)
{
//add this object to the exclude list to avoid circual references in the future
if (excludeList == null) excludeList = new ArrayList();
excludeList.add(o);
callCount++;
StringBuffer tabs = new StringBuffer();
for (int k = 0; k < callCount; k++)
{
tabs.append("\t");
}
StringBuffer buffer = new StringBuffer();
Class oClass = o.getClass();
if (oClass.isArray()) {
buffer.append("\n");
buffer.append(tabs.toString());
buffer.append("[");
for (int i = 0; i < Array.getLength(o); i++)
{
if (i < 0) buffer.append(",");
Object value = Array.get(o, i);
if (value != null)
{
if (excludeList.contains(value))
{
buffer.append("circular reference");
}
else if (value.getClass().isPrimitive() || value.getClass() == java.lang.Long.class || value.getClass() == java.lang.String.class || value.getClass() == java.lang.Integer.class || value.getClass() == java.lang.Boolean.class)
{
buffer.append(value);
}
else
{
buffer.append(dumpFields(value, callCount, excludeList));
}
}
}
buffer.append(tabs.toString());
buffer.append("]\n");
}
else
{
buffer.append("\n");
buffer.append(tabs.toString());
buffer.append("{\n");
while (oClass != null)
{
Field[] fields = oClass.getDeclaredFields();
for (int i = 0; i < fields.length; i++)
{
if (fields[i] == null) continue;
buffer.append(tabs.toString());
fields[i].setAccessible(true);
buffer.append(fields[i].getName());
buffer.append("=");
try
{
Object value = fields[i].get(o);
if (value != null)
{
if (excludeList.contains(value))
{
buffer.append("circular reference");
}
else if ((value.getClass().isPrimitive()) || (value.getClass() == java.lang.Long.class) || (value.getClass() == java.lang.String.class) || (value.getClass() == java.lang.Integer.class) || (value.getClass() == java.lang.Boolean.class))
{
buffer.append(value);
}
else
{
buffer.append(dumpFields(value, callCount, excludeList));
}
}
}
catch (IllegalAccessException e)
{
System.out.println("IllegalAccessException: " + e.getMessage());
}
buffer.append("\n");
}
oClass = oClass.getSuperclass();
}
buffer.append(tabs.toString());
buffer.append("}\n");
}
return buffer.toString();
}
System.out.println(dumpFields(obj, 0, null);
Exception in thread "AWT-EventQueue-0" java.lang.StackOverflowError
at java.lang.reflect.Field.copy(Field.java:127)
at java.lang.reflect.ReflectAccess.copyField(ReflectAccess.java:122)
at sun.reflect.ReflectionFactory.copyField(ReflectionFactory.java:289)
at java.lang.Class.copyFields(Class.java:2739)
at java.lang.Class.getDeclaredFields(Class.java:1743)
at com.gui.ClassName.dumpFields(ClassName.java:627)
public static String dumpFields(Object o, int callCount, IdentityHashMap idHashMap)
{
callCount++;
//add this object to the exclude list to avoid circual references in the future
if (idHashMap == null) idHashMap = new IdentityHashMap();
idHashMap.put(o, o);
//setup string buffer and add fields
StringBuffer tabs = new StringBuffer();
for (int k = 0; k < callCount; k++)
{
tabs.append("\t");
}
StringBuffer buffer = new StringBuffer();
Class oClass = o.getClass();
if (oClass.isArray()) {
buffer.append("\n");
buffer.append(tabs.toString());
buffer.append("[");
for (int i = 0; i < Array.getLength(o); i++)
{
if (i < 0) buffer.append(",");
Object value = Array.get(o, i);
if (value != null)
{
if (idHashMap.containsKey(value))
{
buffer.append("circular reference");
}
else if (value.getClass().isPrimitive() || value.getClass() == java.lang.Long.class || value.getClass() == java.lang.String.class || value.getClass() == java.lang.Integer.class || value.getClass() == java.lang.Boolean.class)
{
buffer.append(value);
}
else
{
buffer.append(dumpFields(value, callCount, idHashMap));
}
}
}
buffer.append(tabs.toString());
buffer.append("]\n");
}
else
{
buffer.append("\n");
buffer.append(tabs.toString());
buffer.append("{\n");
while (oClass != null)
{
Field[] fields = oClass.getDeclaredFields();
for (int i = 0; i < fields.length; i++)
{
if (fields[i] == null) continue;
buffer.append(tabs.toString());
fields[i].setAccessible(true);
buffer.append(fields[i].getName());
buffer.append("=");
try
{
Object value = fields[i].get(o);
if (value != null)
{
if (idHashMap.containsKey(value))
{
buffer.append("circular reference");
}
else if ((value.getClass().isPrimitive()) || (value.getClass() == java.lang.Long.class) || (value.getClass() == java.lang.String.class) || (value.getClass() == java.lang.Integer.class) || (value.getClass() == java.lang.Boolean.class))
{
buffer.append(value);
}
else
{
buffer.append(dumpFields(value, callCount, idHashMap));
}
}
}
catch (IllegalAccessException e)
{
System.out.println("IllegalAccessException: " + e.getMessage());
}
buffer.append("\n");
}
oClass = oClass.getSuperclass();
}
buffer.append(tabs.toString());
buffer.append("}\n");
}
return buffer.toString();
}
//returns all fields of the given object in a string
public static String dumpFields(Object start)
{
class CallLevel
{
public Object target;
public int level;
public CallLevel(Object target, int level)
{
this.target = target;
this.level = level;
}
}
//create a work list
List<CallLevel> workList = new ArrayList<CallLevel>();
workList.add(new CallLevel(start, 0));
//add this object to the exclude list to avoid circual references in the future
IdentityHashMap idHashMap = new IdentityHashMap();
StringBuffer buffer = new StringBuffer();
while (!workList.isEmpty())
{
CallLevel level = workList.remove(workList.size() - 1);
Object o = level.target;
//add this object to the exclude list to avoid circual references in the future
idHashMap.put(o, o);
//setup string buffer and add fields
StringBuffer tabs = new StringBuffer();
int callCount = level.level;
for (int k = 0; k < callCount; k++)
{
tabs.append("\t");
}
callCount++;
Class oClass = o.getClass();
if (oClass.isArray()) {
buffer.append("\n");
buffer.append(tabs.toString());
buffer.append("[");
for (int i = 0; i < Array.getLength(o); i++)
{
if (i < 0) buffer.append(",");
Object value = Array.get(o, i);
if (value != null)
{
if (idHashMap.containsKey(value))
{
buffer.append("circular reference");
}
else if (value.getClass().isPrimitive() || value.getClass() == java.lang.Long.class || value.getClass() == java.lang.String.class || value.getClass() == java.lang.Integer.class || value.getClass() == java.lang.Boolean.class)
{
buffer.append(value);
}
else
{
workList.add(new CallLevel(value, callCount));
}
}
}
buffer.append(tabs.toString());
buffer.append("]\n");
}
else
{
buffer.append("\n");
buffer.append(tabs.toString());
buffer.append("{\n");
while (oClass != null)
{
Field[] fields = oClass.getDeclaredFields();
for (int i = 0; i < fields.length; i++)
{
if (fields[i] == null) continue;
buffer.append(tabs.toString());
fields[i].setAccessible(true);
buffer.append(fields[i].getName());
buffer.append("=");
try
{
Object value = fields[i].get(o);
if (value != null)
{
if (idHashMap.containsKey(value))
{
buffer.append("circular reference");
}
else if ((value.getClass().isPrimitive()) || (value.getClass() == java.lang.Long.class) || (value.getClass() == java.lang.String.class) || (value.getClass() == java.lang.Integer.class) || (value.getClass() == java.lang.Boolean.class))
{
buffer.append(value);
}
else
{
workList.add(new CallLevel(value, callCount));
}
}
}
catch (IllegalAccessException e)
{
System.out.println("IllegalAccessException: " + e.getMessage());
}
buffer.append("\n");
}
oClass = oClass.getSuperclass();
}
buffer.append(tabs.toString());
buffer.append("}\n");
}
}
return buffer.toString();
}
public static String dumpFields(Object start)
{
class CallLevel
{
public Object target;
public int level;
public CallLevel(Object target, int level)
{
this.target = target;
this.level = level;
}
}
//create a work list
List<CallLevel> workList = new ArrayList<CallLevel>();
workList.add(new CallLevel(start, 0));
//create an identity map for object comparison
IdentityHashMap idHashMap = new IdentityHashMap();
//setup a string buffer to return
StringBuffer buffer = new StringBuffer();
while (!workList.isEmpty())
{
CallLevel level = workList.remove(workList.size() - 1);
Object o = level.target;
//add this object to the exclude list to avoid circual references in the future
idHashMap.put(o, o);
//set string buffer for tabs
StringBuffer tabs = new StringBuffer();
int callCount = level.level;
for (int k = 0; k < callCount; k++)
{
tabs.append("\t");
}
//increment the call count for future calls
callCount++;
//set the class for this object
Class oClass = o.getClass();
//if this is an array, dump it's elements, otherwise dump the fields of this object
if (oClass.isArray()) {
buffer.append("\n");
buffer.append(tabs.toString());
buffer.append("[");
for (int i = 0; i < Array.getLength(o); i++)
{
if (i < 0) buffer.append(",");
Object value = Array.get(o, i);
if (value != null)
{
if (value.getClass().isPrimitive())
{
buffer.append(value);
}
else if (idHashMap.containsKey(value))
{
buffer.append("circular reference");
}
else
{
workList.add(new CallLevel(value, callCount));
}
}
}
buffer.append(tabs.toString());
buffer.append("]\n");
}
else
{
buffer.append("\n");
buffer.append(tabs.toString());
buffer.append("{\n");
while (oClass != null)
{
Field[] fields = oClass.getDeclaredFields();
for (int i = 0; i < fields.length; i++)
{
//make sure this field exists
if (fields[i] == null) continue;
//ignore static fields
if (!Modifier.isStatic(fields[i].getModifiers()))
{
buffer.append(tabs.toString());
fields[i].setAccessible(true);
buffer.append(fields[i].getName());
buffer.append("=");
try
{
Object value = fields[i].get(o);
if (value != null)
{
if (fields[i].getType().isPrimitive())
{
buffer.append(value);
}
else if (idHashMap.containsKey(value))
{
buffer.append("circular reference");
}
else
{
workList.add(new CallLevel(value, callCount));
}
}
}
catch (IllegalAccessException e)
{
System.out.println("IllegalAccessException: " + e.getMessage());
}
buffer.append("\n");
}
}
oClass = oClass.getSuperclass();
}
buffer.append(tabs.toString());
buffer.append("}\n");
}
}
return buffer.toString();
}
Exception in thread "AWT-EventQueue-0" java.lang.OutOfMemoryError: Java heap space
at java.util.Arrays.copyOfRange(Arrays.java:3209)
at java.lang.String.<init>(String.java:215)
at java.lang.StringBuffer.toString(StringBuffer.java:585)
at com.gui.ClassName.dumpFields(ClassName.java:702)
at com.gui.ClassName.setTextArea(ClassName.java:274)
at com.gui.ClassName.access$8(ClassName.java:272)
at com.gui.ClassName$1.valueChanged(ClassName.java:154)
at javax.swing.JList.fireSelectionValueChanged(JList.java:1765)
at javax.swing.JList$ListSelectionHandler.valueChanged(JList.java:1779)
at javax.swing.DefaultListSelectionModel.fireValueChanged(DefaultListSelectionModel.java:167)
at javax.swing.DefaultListSelectionModel.fireValueChanged(DefaultListSelectionModel.java:147)
at javax.swing.DefaultListSelectionModel.fireValueChanged(DefaultListSelectionModel.java:194)
at javax.swing.DefaultListSelectionModel.changeSelection(DefaultListSelectionModel.java:388)
at javax.swing.DefaultListSelectionModel.changeSelection(DefaultListSelectionModel.java:398)
at javax.swing.DefaultListSelectionModel.setSelectionInterval(DefaultListSelectionModel.java:442)
at javax.swing.JList.setSelectedIndex(JList.java:2179)
at com.gui.ClassName$1.valueChanged(ClassName.java:138)
at javax.swing.JList.fireSelectionValueChanged(JList.java:1765)
at javax.swing.JList$ListSelectionHandler.valueChanged(JList.java:1779)
at javax.swing.DefaultListSelectionModel.fireValueChanged(DefaultListSelectionModel.java:167)
at javax.swing.DefaultListSelectionModel.fireValueChanged(DefaultListSelectionModel.java:137)
at javax.swing.DefaultListSelectionModel.setValueIsAdjusting(DefaultListSelectionModel.java:668)
at javax.swing.JList.setValueIsAdjusting(JList.java:2110)
at javax.swing.plaf.basic.BasicListUI$Handler.mouseReleased(BasicListUI.java:2783)
at java.awt.AWTEventMulticaster.mouseReleased(AWTEventMulticaster.java:273)
at java.awt.Component.processMouseEvent(Component.java:6263)
at javax.swing.JComponent.processMouseEvent(JComponent.java:3255)
at java.awt.Component.processEvent(Component.java:6028)
at java.awt.Container.processEvent(Container.java:2041)
at java.awt.Component.dispatchEventImpl(Component.java:4630)
at java.awt.Container.dispatchEventImpl(Container.java:2099)
at java.awt.Component.dispatchEvent(Component.java:4460)
最佳答案
+1 使用 IdentityHashMap
解决问题。
原因是您的方法当前取决于每个访问对象的类如何实现 equals
, 自 List.contains(Object)使用 equals
作为比较的依据。如果一个类(class)的 equals()
方法被破坏,并错误地返回 false
即使将自身作为比较对象传递,您也会得到一个无限循环,因为调用 List.contains
始终返回 false 并且始终针对该类型的对象遍历该对象子图。
此外,如果您有两个或多个对象是不同的实例,但在值上被视为相等(即 equals 返回 true),则只会写出其中一个。这是可取的还是问题取决于您的用例。
使用 IdentityHashMap
将避免这两个问题。
顺便说一句 - 如果你想根据调用深度缩进,不要忘记递增 callCount
递归调用 dumpFields
.
编辑:我认为代码工作正常。问题是您确实遇到了堆栈溢出。如果您有一个大型对象图,就会发生这种情况。例如,想象一个包含 3000 个元素的链表。这将涉及 3000 次递归调用,我很确定这会破坏默认堆栈大小的堆栈。
要解决此问题,您可以将堆栈的大小 (vmarg -Xss) 增加到足够大以处理您预期的对象图大小(不是一个强大的解决方案!),或者用显式数据结构替换堆栈的使用。
而不是堆栈,创建一个工作列表。此列表包含您已经看到但尚未处理的对象。您只需将对象添加到您的工作列表中,而不是递归调用 dumpFields。该方法的主体是一个 while 循环,只要列表中有项目,它就会迭代。
例如。
class CallLevel
{
CallLevel(Object target, int level) {
this.target = target; this.level = level;
}
Object target;
int level;
}
public static String dumpFields(Object start)
{
List<CallLevel> workList = new ArrayList<CallLevel>();
workList.add(new Calllevel(start,0));
Map idHashMap = new IdentityHashMap();
while (!workList.isEmpty()) {
CallLevel level = workList.removeAt(workList.size()-1);
Object o = level.object;
//add this object to the exclude list to avoid circual references in the future
idHashMap.put(, o);
//setup string buffer and add fields
StringBuffer tabs = new StringBuffer();
int callCount = level.level;
for (int k = 0; k < callCount; k++)
{
tabs.append("\t");
}
callCount++;
StringBuffer buffer = new StringBuffer();
Class oClass = o.getClass();
if (oClass.isArray()) {
buffer.append("\n");
buffer.append(tabs.toString());
buffer.append("[");
for (int i = 0; i < Array.getLength(o); i++)
{
if (i < 0) buffer.append(",");
Object value = Array.get(o, i);
if (value != null)
{
if (idHashMap.containsKey(value))
{
buffer.append("circular reference");
}
else if (value.getClass().isPrimitive() || value.getClass() == java.lang.Long.class || value.getClass() == java.lang.String.class || value.getClass() == java.lang.Integer.class || value.getClass() == java.lang.Boolean.class)
{
buffer.append(value);
}
else
{
workList.add(new Calllevel(value, callCount));
}
}
}
buffer.append(tabs.toString());
buffer.append("]\n");
}
else
{
buffer.append("\n");
buffer.append(tabs.toString());
buffer.append("{\n");
while (oClass != null)
{
Field[] fields = oClass.getDeclaredFields();
for (int i = 0; i < fields.length; i++)
{
if (fields[i] == null) continue;
buffer.append(tabs.toString());
fields[i].setAccessible(true);
buffer.append(fields[i].getName());
buffer.append("=");
try
{
Object value = fields[i].get(o);
if (value != null)
{
if (idHashMap.containsKey(value))
{
buffer.append("circular reference");
}
else if ((value.getClass().isPrimitive()) || (value.getClass() == java.lang.Long.class) || (value.getClass() == java.lang.String.class) || (value.getClass() == java.lang.Integer.class) || (value.getClass() == java.lang.Boolean.class))
{
buffer.append(value);
}
else
{
workList.add(new CallLevel(value, callCount));
}
}
}
catch (IllegalAccessException e)
{
System.out.println("IllegalAccessException: " + e.getMessage());
}
buffer.append("\n");
}
oClass = oClass.getSuperclass();
}
buffer.append(tabs.toString());
buffer.append("}\n");
}
return buffer.toString();
Modifier.isStatic(field.getModifiers())
. Double
- 这是一种简化 - JDK 实际上会重用一些对象,请参阅
Integer.valueOf()
的来源,但一般来说,当一个基元被装箱时会创建一个新对象。)由于这些基元生成唯一的新对象,因此根据排除映射检查这些几乎没有意义。因此,将primite测试放在首位。顺便提一下,支票
value.getClass().isPrimitive()
将始终返回 false - 装箱类型绝不是原始类型。您可以改为使用字段的声明类型,例如
field.getType().isPrimitive()
.
关于Java:使用反射转储对象信息时如何避免循环引用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2746267/
我的一位教授给了我们一些考试练习题,其中一个问题类似于下面(伪代码): a.setColor(blue); b.setColor(red); a = b; b.setColor(purple); b
我似乎经常使用这个测试 if( object && object !== "null" && object !== "undefined" ){ doSomething(); } 在对象上,我
C# Object/object 是值类型还是引用类型? 我检查过它们可以保留引用,但是这个引用不能用于更改对象。 using System; class MyClass { public s
我在通过 AJAX 发送 json 时遇到问题。 var data = [{"name": "Will", "surname": "Smith", "age": "40"},{"name": "Wil
当我尝试访问我的 View 中的对象 {{result}} 时(我从 Express js 服务器发送该对象),它只显示 [object][object]有谁知道如何获取 JSON 格式的值吗? 这是
我有不同类型的数据(可能是字符串、整数......)。这是一个简单的例子: public static void main(String[] args) { before("one"); }
嗨,我是 json 和 javascript 的新手。 我在这个网站找到了使用json数据作为表格的方法。 我很好奇为什么当我尝试使用 json 数据作为表时,我得到 [Object,Object]
已关闭。此问题需要 debugging details 。目前不接受答案。 编辑问题以包含 desired behavior, a specific problem or error, and the
我听别人说 null == object 比 object == null check 例如: void m1(Object obj ) { if(null == obj) // Is thi
Match 对象 提供了对正则表达式匹配的只读属性的访问。 说明 Match 对象只能通过 RegExp 对象的 Execute 方法来创建,该方法实际上返回了 Match 对象的集合。所有的
Class 对象 使用 Class 语句创建的对象。提供了对类的各种事件的访问。 说明 不允许显式地将一个变量声明为 Class 类型。在 VBScript 的上下文中,“类对象”一词指的是用
Folder 对象 提供对文件夹所有属性的访问。 说明 以下代码举例说明如何获得 Folder 对象并查看它的属性: Function ShowDateCreated(f
File 对象 提供对文件的所有属性的访问。 说明 以下代码举例说明如何获得一个 File 对象并查看它的属性: Function ShowDateCreated(fil
Drive 对象 提供对磁盘驱动器或网络共享的属性的访问。 说明 以下代码举例说明如何使用 Drive 对象访问驱动器的属性: Function ShowFreeSpac
FileSystemObject 对象 提供对计算机文件系统的访问。 说明 以下代码举例说明如何使用 FileSystemObject 对象返回一个 TextStream 对象,此对象可以被读
我是 javascript OOP 的新手,我认为这是一个相对基本的问题,但我无法通过搜索网络找到任何帮助。我是否遗漏了什么,或者我只是以错误的方式解决了这个问题? 这是我的示例代码: functio
我可以很容易地创造出很多不同的对象。例如像这样: var myObject = { myFunction: function () { return ""; } };
function Person(fname, lname) { this.fname = fname, this.lname = lname, this.getName = function()
任何人都可以向我解释为什么下面的代码给出 (object, Object) 吗? (console.log(dope) 给出了它应该的内容,但在 JSON.stringify 和 JSON.parse
我正在尝试完成散点图 exercise来自免费代码营。然而,我现在只自己学习了 d3 几个小时,在遵循 lynda.com 的教程后,我一直在尝试确定如何在工具提示中显示特定数据。 This code
我是一名优秀的程序员,十分优秀!