Ответ 1
Как и в случае с Java 7, разрешение перегрузки метода должно выполняться до того, как любая информация о целевом типе от метода, который вы вызываете, может быть принята во внимание, чтобы попытаться вывести переменную типа T
в объявление func
. Это кажется глупым, поскольку мы все можем видеть, что в этом случае существует один и только один метод с именем func
, однако он задан JLS и является поведением javac
из Java 7.
Компиляция выполняется следующим образом: во-первых, компилятор видит, что он компилирует вызов статического метода класса Bar с именем func. Чтобы выполнить разрешение перегрузки, он должен выяснить, с какими параметрами вызывается метод. Несмотря на то, что это тривиальный случай, он все равно должен это делать, и пока он не сделал этого, у него нет никакой информации об официальных параметрах метода, доступных для его помощи. Фактические параметры состоят из одного аргумента, вызов Foo.create()
, который объявляется как возвращающий Foo<T>
. Опять же, без критериев из целевого метода, можно только вывести, что возвращаемый тип - это стирание Foo<T>
, которое Foo<Object>
, и оно делает это.
Разрешение перегрузки метода не выполняется, так как ни одна из перегрузок func
не совместима с фактическим параметром Foo<Object>
, и при этом испускается ошибка.
Это, конечно, очень неудачно, так как мы все можем видеть, что если информация может просто перетекать в другом направлении, от цели метода обращается к сайту вызова, тип может быть легко выведен и не будет ошибка. И на самом деле компилятор в Java 8 может сделать именно это и делает. Как было сказано в другом ответе, этот более богатый тип ввода очень полезен для lambdas, которые добавляются в Java 8, и к расширениям Java API, которые используются для использования lambdas.
Вы можете загрузить предварительную версию Java 8 с JSR 335 lambdas из предыдущей ссылки. Он компилирует код в вопросе без каких-либо предупреждений или ошибок.