Почему и как этот код Java компилируется?

Следующий код печатает "String"

public class Riddle {

    public static void main(String[] args) {
        hello(null);
    }

    public static void hello(Object o) {
        System.out.println("Object");
    }


    public static void hello(String s) {
        System.out.println("String");
    }

}

Почему этот код компилируется? Не является ли неопределенным двузначный?

Например, следующий код НЕ компилируется из-за неоднозначной подписи.

public class Riddle {

    public static void main(String[] args) {
        hello(null);
    }

    public static void hello(Object o) {
        System.out.println("Object");
    }

    public static void hello(Integer o) {
        System.out.println("Integer");
    }

    public static void hello(String s) {
        System.out.println("String");
    }

}

Может кто-нибудь объяснить, почему первый пример может скомпилироваться без двусмысленных ошибок?

Ответ 1

Во втором случае компиляция не выполняется, поскольку компилятор не может решить между методом, который принимает Integer и метод, который принимает строку, где, как и в случае с первым, компилятор может понять это.

Ссылка: http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.12.2

Ответ 2

пожалуйста, см. JLS §15.12.2

следующий порядок решения метода для назначения вызова важен когда такой же тип данных типа,

  • (для примитивного типа данных) точное совпадение типа данных и вызов его. 1.1, если нет, тогда вызывается более широко, чем этот доступный тип данных, затем вызывайте его.
  • для типа Wrapper типа Data или его родителя, если выше не удалось.
  • Vararg этого типа данных будет соответствовать, если выше 2-неудачно.