我写了一个方法来返回包中所有静态变量的字符串表示。它以递归方式扫描这些对象以获取更多变量,依此类推。问题是一些swing对象包含对其父项的引用,并产生StackOverflowError
。我的问题是,如何防止这种无限递归?我正在考虑列出已经列出的对象,但是如果我有两个引用相同内容的变量会发生什么?它只列出其中一个,我不想要。
如果检测到无限循环,它应该返回诸如“无限递归”之类的东西:
var1 = {
var2 = {
var1 = Infinite Recursion
}
}
要运行它,请致电dumpVarables(true)
。深变量是一个标志,告诉它是否保留指定的包。
private static ArrayList<Class<?>> getClassesForPackage(Package pkg) {//This makes a list of all classes in a package
String pkgname = pkg.getName();
ArrayList<Class<?>> classes = new ArrayList<Class<?>>();
// Get a File object for the package
File directory = null;
String fullPath;
String relPath = pkgname.replace('.', '/');
// System.out.println("ClassDiscovery: Package: " + pkgname + " becomes Path:" + relPath);
URL resource = ClassLoader.getSystemClassLoader().getResource(relPath);
// System.out.println("ClassDiscovery: Resource = " + resource);
if (resource == null) {
throw new RuntimeException("No resource for " + relPath); //$NON-NLS-1$
}
fullPath = resource.getFile();
// System.out.println("ClassDiscovery: FullPath = " + resource);
try {
directory = new File(resource.toURI());
}
catch (URISyntaxException e) {
throw new RuntimeException(pkgname + " (" + resource + ") does not appear to be a valid URL / URI. Strange, since we got it from the system...", e); //$NON-NLS-1$//$NON-NLS-2$
}
catch (IllegalArgumentException e) {
directory = null;
}
// System.out.println("ClassDiscovery: Directory = " + directory);
if (directory != null && directory.exists()) {
// Get the list of the files contained in the package
String[] files = directory.list();
for (int i = 0; i < files.length; i++) {
// we are only interested in .class files
if (files[i].endsWith(".class")) { //$NON-NLS-1$
// removes the .class extension
String className = pkgname + '.' + files[i].substring(0, files[i].length() - 6);
// System.out.println("ClassDiscovery: className = " + className);
try {
classes.add(Class.forName(className));
}
catch (ClassNotFoundException e) {
throw new RuntimeException("ClassNotFoundException loading " + className); //$NON-NLS-1$
}
}
}
} else {
try {
String jarPath = fullPath.replaceFirst("[.]jar[!].*", ".jar").replaceFirst("file:", ""); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
JarFile jarFile = new JarFile(jarPath);
Enumeration<JarEntry> entries = jarFile.entries();
while (entries.hasMoreElements()) {
JarEntry entry = entries.nextElement();
String entryName = entry.getName();
if (entryName.startsWith(relPath) && entryName.length() > relPath.length() + "/".length()) { //$NON-NLS-1$
// System.out.println("ClassDiscovery: JarEntry: " + entryName);
String className = entryName.replace('/', '.').replace('\\', '.').replace(".class", ""); //$NON-NLS-1$ //$NON-NLS-2$
// System.out.println("ClassDiscovery: className = " + className);
try {
classes.add(Class.forName(className));
}
catch (ClassNotFoundException e) {
throw new RuntimeException("ClassNotFoundException loading " + className); //$NON-NLS-1$
}
}
}
}
catch (IOException e) {
throw new RuntimeException(pkgname + " (" + directory + ") does not appear to be a valid package", e); //$NON-NLS-1$ //$NON-NLS-2$
}
}
return classes;
}
private static String getSpacing(int level) {//Creates fancy spacing to allow you to read the output better
String str = "";
for (int i = 0; i < level; i++) {
str += " ";
}
return str;
}
public static String dumpVarables(boolean deep) {//This is what returns a string of all static varables, you can simply run System.out.println(dumpVarables(true)); to work this
String str = ""; //$NON-NLS-1$
//Get a list of all classes in the "derby" package
for (Class clazz : getClassesForPackage(Package.getPackage("derby"))) { //$NON-NLS-1$
Field[] declaredFields = clazz.getDeclaredFields();
for (Field field : declaredFields) {
if (java.lang.reflect.Modifier.isStatic(field.getModifiers())) {
field.setAccessible(true);
str += clazz.getName() + "." + field.getName();
try {
str += " = " + dumpVarables(field.get(null), 1, deep) + "\n";
}
catch (IllegalArgumentException | IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
return str;
}
private static String dumpVarables(Object object, int level, boolean deep) {
//If object is null, return null
if (object == null) {
return "null";
}
//If object is one of these types, return its string representation
if (object instanceof String || object instanceof Byte || object instanceof Short || object instanceof Integer || object instanceof Long || object instanceof Float || object instanceof Double || object instanceof Boolean || object instanceof Character) {
return object.toString();
}
// Test if the object is an array and list it if it is
String result = "";
if (object.getClass().isArray()) {
result += "[";
Object[] objArray = (Object[]) object;
for (int i = 0; i < objArray.length; i++) {
result += dumpVarables(objArray[i], level, deep);
if (i + 1 < objArray.length) {
result += ", ";
}
}
result += "]";
return result;
}
String pkg = object.getClass().getPackage().getName();
// Test if the object is outside of our package
if (!(pkg.equals("derby") || pkg.equals("utils"))) {
//If we want to go deeper, we can go outside the derby and utils package
if (!deep) {
return object.toString();
}
}
Class<?> clazz = object.getClass();
result += clazz.getName();
Field[] fields = clazz.getDeclaredFields();
String fieldStuff = "";
for (Field field : fields) {
String fieldName = field.getName();
//Make sure the field is not a reference to it's self or it is static
if (fieldName.equals("this$0") || Modifier.isStatic(field.getModifiers())) { //$NON-NLS-1$
continue;
}
//Some fancy formatting
fieldStuff += getSpacing(level);
fieldStuff += fieldName;
fieldStuff += " = "; //$NON-NLS-1$
field.setAccessible(true);
try {
fieldStuff += dumpVarables(field.get(object), level + 1, deep);
}
catch (IllegalArgumentException | IllegalAccessException e) {
e.printStackTrace();
}
fieldStuff += "\n"; //$NON-NLS-1$
}
//Some fancy formatting
if (fieldStuff.length() > 0) {
result += " {\n"; //$NON-NLS-1$
}
result += fieldStuff;
if (fieldStuff.length() > 0) {
result += getSpacing(level - 1);
result += "}"; //$NON-NLS-1$
}
return result.toString();
}
答案 0 :(得分:1)
听起来你想要的不仅仅是一个类何时被重新访问,而是当它是当前类的祖先的一部分时(因此形成一个循环)。
这样,解决方案很简单:跟踪当前的祖先(例如,作为祖先类的列表),在你递归时添加它,然后从中删除返回。
然后,当你到达祖先的一个班级时,将其作为递归参考报告并继续前进。