【问题标题】:Different data types in javajava中的不同数据类型
【发布时间】:2017-06-16 03:33:06
【问题描述】:

我在运行时使用反射从 Java 对象中提取字段类型。这些字段被分类为:

  • 原始类型
  • 包名称以 Java.lang.* 开头的字段
  • 包名称以 Java.util.* 开头的字段
  • 数组类型

对于字段中的自定义对象(用户定义):再次探索它们的字段和分类的各自字段。(递归调用)

我想知道上述分类是否足以用于任何对象,或者是否需要一些额外的类别才能进行更有意义的分类。

【问题讨论】:

  • 不清楚您认为什么是“有意义的分类”。
  • 通过有意义的分类,我的意思是上述分类是否能够处理任何通用对象。实际上,在分类后,我正在尝试获取字段值。因此,当我看到原始类型时,我可以获得它的值,或者 java.util.* 类型,那么我确定它必须是列表、映射(可以使用迭代器访问值)或其他类型,如日历、日期(值可以通过 toString()) 访问。 java.lang.* 和 Array 类型也是如此。那么这些类别是否足以访问用户为该对象设置的值?
  • 来自另一个包的自定义类型呢?
  • 我想这里的自定义类型是指用户定义的类型。如果是这种情况,那么它将被视为自定义对象,并且递归调用(现在将此自定义对象作为参数)会将其分类到给定的类别中
  • 所以你基本上忽略了自定义类型的字段?我仍然不清楚这里的目标是什么。

标签: java object reflection field


【解决方案1】:

我做这样的事情是为了调试,我只是检查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(可能不包括StringInteger 等已知值类型),因此在两个对象的情况下不会出现无限递归互相参考。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-12-01
    • 2013-08-11
    • 1970-01-01
    • 2017-07-18
    • 2017-08-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多