我使用反射在运行时从Java对象中提取字段类型。这些字段分类为:
对于字段中的自定义对象(用户定义):再次针对其字段及其各自的字段进行分类。(递归调用)
我想知道上述分类对于任何对象是否足够,或者需要一些额外的类别来进行更有意义的分类。
答案 0 :(得分:0)
我做这样的事情用于调试,我只检查Iterable
,有时检查Map
。试图静态地考虑每种可能的类型是一个傻瓜的差事。如果你想处理任何可能的类型,一个好主意就是创建一个注册转换器函数的简单方法。然后API的客户端基本上可以做任何他们想做的事情。
这是一个相对较快的例子:
package mcve.reflect;
import java.lang.reflect.*;
import java.io.*;
import java.util.*;
import java.util.stream.*;
import java.util.function.*;
public interface DebugReadout {
/**
* Prints a readout of all instance fields in {@code this} to the
* specified print stream.
*
* @param out
* @throws NullPointerException
*/
default void readout(PrintStream out) {
Class<?> clazz = getClass();
out.printf("%s {%n", clazz.getSimpleName());
do {
for (Field f : clazz.getDeclaredFields()) {
if (!Modifier.isStatic(f.getModifiers())) {
String value;
try {
f.setAccessible(true);
value = Details.toString(f.get(this));
} catch (ReflectiveOperationException
| SecurityException x) {
value = "UNAVAILABLE";
}
out.printf(" %s = %s%n", f.getName(), value);
}
}
} while((clazz = clazz.getSuperclass()) != Object.class);
out.printf("}%n");
}
/**
* Registers a converter function.
*
* @param <T>
* @param type
* @param fn
* @throws NullPointerException
*/
static <T> void put(Class<T> type, Function<? super T, String> fn) {
Objects.requireNonNull(type);
Objects.requireNonNull(fn);
Details.CONVERTERS.put(type, fn);
}
/**
* Returns a converter function or {@code null} if one didn't exist.
*
* @param <T>
* @param type
* @return a converter function
*/
@SuppressWarnings("unchecked")
static <T> Function<? super T, String> get(Class<T> type) {
Objects.requireNonNull(type);
synchronized (Details.CONVERTERS) {
Function<?, String> fn = Details.CONVERTERS.get(type);
if (fn == null) {
for (Class<?> key : Details.CONVERTERS.keySet()) {
if (key.isAssignableFrom(type)) {
fn = Details.CONVERTERS.get(key);
break;
}
}
}
return (Function<? super T, String>) fn;
}
}
}
class Details {
static final Map<Class<?>, Function<?, String>> CONVERTERS =
Collections.synchronizedMap(new HashMap<>());
static <T> String toString(T obj) {
if (obj == null) {
return "null";
}
@SuppressWarnings("unchecked")
Function<? super T, String> fn =
(Function<? super T, String>)
DebugReadout.get(obj.getClass());
if (fn != null) {
return fn.apply(obj);
}
if (obj.getClass().isArray()) {
return IntStream.range(0, Array.getLength(obj))
.mapToObj(i -> toString(Array.get(obj, i)))
.collect(Collectors.joining(", ", "[", "]"));
}
if (obj instanceof Iterable<?>) {
return StreamSupport.stream(((Iterable<?>) obj).spliterator(), false)
.map(e -> toString(e))
.collect(Collectors.joining(", ", "[", "]"));
}
if (obj instanceof Map<?, ?>) {
return toString(((Map<?, ?>) obj).entrySet());
}
return obj.toString();
}
}
一个更健壮的例程会保留到目前为止看到的每个对象的IdentityHashMap
(可能不包括String
和Integer
等已知值类型,因此您不会最终得到在两个对象相互引用的情况下无限递归。