简体   繁体   English

Java静态多态(重载)和泛型之间的继承

[英]Java static polymorphism (overloading) and inheritance between generics

Java 11 (may be irrelevant): Java 11(可能无关紧要):

public static String toString(Object obj) {
    return ReflectionToStringBuilder.toString(obj, ToStringStyle.SHORT_PREFIX_STYLE);
}

public static String toString(Collection<Object> collection) {
    return collection.stream()
            .map(SaLogUtils::toString)
            .collect(Collectors.joining(", ", "[", "]"));
}

public static void main(String[] args) {
    List<Integer> list = List.of(Integer.valueOf(1));
    System.out.println(SaLogUtils.toString(list));
    System.out.println(SaLogUtils.toString(List.of(Integer.valueOf(1))));
}

Surprising output:令人惊讶的输出:

// from toString(Object)
ImmutableCollections.List12[e0=1,e1=<null>]
// from toString(Collection<Object>)
[Integer[value=1]]

Why does Java statically choose different methods?为什么Java静态选择不同的方法?

When there are multiple overloads which could be invoked, Java chooses the most specific applicable method :当可以调用多个重载时,Java 会选择最具体的适用方法

The informal intuition is that one method is more specific than another if any invocation handled by the first method could be passed on to the other one without a compile-time error.非正式的直觉是,如果第一个方法处理的任何调用都可以传递给另一个方法而没有编译时错误,则一个方法比另一个方法更具体。 In cases such as an explicitly typed lambda expression argument (§15.27.1) or a variable arity invocation (§15.12.2.4), some flexibility is allowed to adapt one signature to the other.在诸如显式类型化的 lambda 表达式参数(第 15.27.1 节)或变量参数调用(第 15.12.2.4 节)之类的情况下,允许一些灵活性使一个签名适应另一个签名。


toString(Collection<Object>) isn't applicable for a List<Integer> , because a List<Integer> isn't a List<Object> , so it's not a Collection<Object> either. toString(Collection<Object>)不适用于List<Integer> ,因为List<Integer>不是List<Object> ,所以它也不是Collection<Object> As such, only the toString(Object) method is applicable, so that's the one that is invoked.因此,只有toString(Object)方法是适用的,所以它是被调用的方法。


toString(Collection<Object>) is applicable for List.of(someInteger) because that List.of is a polyexpression: it could be List<Integer> , it could be List<Object> , it could be List<Serializable> . toString(Collection<Object>)适用于List.of(someInteger)因为List.of是一个多表达式:它可以是List<Integer> ,它可以是List<Object> ,它可以是List<Serializable>

Since both toString(Object) and toString(Collection<Object>) are applicable, it has to choose one or the other (or declare it ambiguous).由于toString(Object)toString(Collection<Object>)都适用,它必须选择其中之一(或声明它不明确)。 The Collection overload is more specific because: Collection重载更具体,因为:

  • Anything you pass to toString(Collection<Object>) can also be passed to toString(Object)你传递给toString(Collection<Object>)任何东西也可以传递给toString(Object)
  • But there are things you can pass to toString(Object) that can't be passed to toString(Collection<Object>) (such as new Object() ).但是有些东西可以传递给toString(Object)而不能传递给toString(Collection<Object>) (例如new Object() )。

This makes the toString(Collection<Object>) more specific, so this is the one that is chosen.这使得toString(Collection<Object>)更加具体,所以这是被选择的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM