通过通用方法进行重载

时间:2015-08-27 13:40:43

标签: java generics

我的动机是创建一组名为toString()的重载函数,它接受任何对象(或者至少是我感兴趣的对象)并创建一个对调试有用的字符串。然后我也想要一个out()方法,而不必重新创建相同(繁琐)的重载。

我看到我用这段代码得到的是out()中的toString(e)总是调用toString(Object)。在研究泛型之后,我无法看到这种方法。因此,如果有人能够了解如何做到这一点,我将不胜感激。

总结一下:

  • 是否有一种优雅的方法来实现out()方法,利用toString()的退出重载。
  • 这可以用泛型来完成吗?

    public class A3 {
    
        static <E> void out(E e){
            System.out.println(toString(e));
        }
    
        static String toString(Object o){
            return "Object";
        }
    
        static String toString(String str){
            return "String";
        }
    
        static String toString(Integer i){
            return "Integer";
        }
    
        static String toString(SomeObject o){
            return "A description of the object";
        }
    
        public static void main(String[] args) {
            out("");
            out(1);
        }
    
    }
    
编辑:澄清意义的扩展示例。

5 个答案:

答案 0 :(得分:3)

在编译时确定调用哪个方法。如果你想要动态检查,你必须自己编写代码。

唯一的方法是使用一串ifinstanceof支票。

static <E> void out(E e){
    Object o = e instanceof String ? toString((String) e) :
               e instanceof Integer ? toString((Integer) e) :
               toString(e);
    System.out.println(o);
}

或者更好的选择是实施

static String toString(Object o) {
    return o instanceof String ? "String" :
           o instanceof Integer ? "Integer" :
               "Object";
}

注意:除非您这样做,否则toString((Object) "hello")将返回&#34;对象&#34;

答案 1 :(得分:3)

可能有多种方法可以实现实际想要实现的目标。根据您提到的代码和约束,可能有多种方法可以实现您想要实现的目标。但着眼于这一点:

  

是否有一种优雅的方法来实现out()方法,利用toString()的退出重载。

为了利用这些方法,您必须调度到所需的方法。该方法必须在编译时已知,或者在运行时根据给定对象的类型确定。但是,这不能基于泛型和语言内部method overload resolution来完成,因为在编译期间,泛型参数基本上被Object替换。

解决此问题的一种方法是在公共地图中为所需的Function方法注册toString,并在运行时查找这些函数。

请注意,这不一定是您实际想要做的“好”解决方案,而是以一种通用且易于扩展的方式显示“利用现有的过载”的一种方式。

import java.util.LinkedHashMap;
import java.util.Map;
import java.util.function.Function;

public class GenericToString
{
    private static final Map<Class<?>, Function<?, String>> 
        TO_STRING_FUNCTIONS = new LinkedHashMap<>();
    private static <C> void register(Class<C> c, Function<C, String> f)
    {
        TO_STRING_FUNCTIONS.put(c, f);
    }
    static
    {
        register(Object.class, x -> toString(x));
        register(String.class, x -> toString(x));
        register(Integer.class, x -> toString(x));
    }

    public static void main(String[] args)
    {

        out("x");
        out(1);
        out(1.0);
    }

    static void out(Object object)
    {
        System.out.println(toStringDispatcher(object));
    }

    static String toString(Object o)
    {
        return "Object: "+o;
    } 

    static String toString(String s)
    {
        return "String: "+s;
    }

    static String toString(Integer i)
    {
        return "Integer: "+i;
    }    

    private static String toStringDispatcher(Object object)
    {
        if (object == null)
        {
            return "null";
        }
        Function<?, String> f = TO_STRING_FUNCTIONS.get(object.getClass());
        if (f != null)
        {
            @SuppressWarnings("unchecked")
            Function<Object, String> g = (Function<Object, String>)f;
            return g.apply(object);
        }
        return toString(object);
    }

}

答案 2 :(得分:1)

你必须使用反射来实现这个目标(如果你可以使用它),

Method method = A3.class.getDeclaredMethod("toString", e.getClass());
System.out.println(method.invoke(null, e));

这将根据toString()参数的类调用e方法。

答案 3 :(得分:0)

您可以在代码中获取该类的名称并将其返回。

static <E> void out(E e){
    System.out.println(toString(e));
}

static String toString(Object o){
    return o.getClass().getName();
}

public static void main(String[] args) {
    out("");
    out(1);
}

答案 4 :(得分:-1)

public class Test
{

    static void out(Handler<?> h)
    {
        System.out.println(h.ref.getClass());
    }

    private static final class Handler<T>
    {

        final T ref;

        Handler(T ref)
        {
            this.ref = ref;
        }
    }

    public static void main(String[] args)
    {
        out(new Handler<>("1"));
        out(new Handler<>(new Integer(1)));
        out(new Handler<>(new Double(1)));
        out(new Handler<>(new ArrayList<HashMap<String, Socket>>()));
    }
}

结果

class java.lang.String
class java.lang.Integer
class java.lang.Double
class java.util.ArrayList