Java stati c полиморфизм (перегрузка) и наследование между дженериками - PullRequest
6 голосов
/ 04 февраля 2020

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))));
}

Удивительный результат:

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

Почему Java статически выбирает разные методы?

1 Ответ

11 голосов
/ 04 февраля 2020

При наличии нескольких перегрузок, которые могут быть вызваны, Java выбирает наиболее конкретный c применимый метод :

Неформальная интуиция заключается в том, что один метод более укажите c чем другое, если любой вызов, обработанный первым методом, может быть передан другому без ошибки времени компиляции. В таких случаях, как явно заданный аргумент лямбда-выражения (§15.27.1) или вызов переменной arity (§15.12.2.4), допускается некоторая гибкость для адаптации одной подписи к другой.


toString(Collection<Object>) не применимо для List<Integer>, потому что a List<Integer> не является List<Object>, поэтому это также не Collection<Object>. Таким образом, применим только метод toString(Object), поэтому он вызывается.


toString(Collection<Object>) применим для List.of(someInteger), потому что List.of является полиэкспрессией: это может быть List<Integer>, это может быть List<Object>, это может быть List<Serializable>.

Поскольку применимы как toString(Object), так и toString(Collection<Object>), он должен выбрать один или другой (или объявить его неоднозначным) , Перегрузка Collection более специфична c, потому что:

  • Все, что вы передаете в toString(Collection<Object>), также может быть передано в toString(Object)
  • Но есть вещи, которые вы можете передать на toString(Object), который не может быть передан на toString(Collection<Object>) (например, new Object()).

Это делает toString(Collection<Object>) более точным c, так что это тот, который выбран.

...