为什么javac可以推断用作参数的函数的泛型类型参数?

前端之家收集整理的这篇文章主要介绍了为什么javac可以推断用作参数的函数的泛型类型参数?前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
在下面的示例中,为什么编译器能够推断出在Foo.test()中第一次调用Foo.create()的通用参数,但是在第二个样例中却不能这么做?我正在使用 Java 6.
public class Nonsense {
    public static class Bar {
        private static void func(Foo<String> arg) { }
    }

    public static class Foo<T> {

        public static <T> Foo<T> create() {
            return new Foo<T>();
        }

        private static void test() {
            Foo<String> foo2 = Foo.create(); // compiles
            Bar.func(Foo.create());          // won't compile
            Bar.func(Foo.<String>create());  // fixes the prev line
        }
    }
}

(编译错误是Nonsense.Bar类型的func(Nonsense.Foo)方法不适用于参数(Nonsense.Foo)).

注意:我明白编译器错误可以通过test()中的第三行修复 – 我很好奇是否有一个特定的限制,阻止编译器能够推断类型.在我看来,这里有足够的语境.

解决方法

从Java 7开始,方法重载分辨率必须在您调用方法的任何目标类型信息被考虑之前进行,以便在func的声明中推断类型变量T.这似乎是愚蠢的,因为我们都可以看到,在这种情况下,只有一个名为func的方法,然而,它是由JLS强制执行的,是Java 7中javac的行为.

编译进行如下:首先,编译器看到它正在编译一个名为func的类Bar的静态方法调用.要执行重载分辨率,它必须找出调用方法的参数.尽管这是一个微不足道的情况,它仍然必须这样做,直到它这样做,它没有关于可用来帮助它的方法的正式参数的任何信息.实际参数包括一个参数,调用Foo.create(),它被声明为返回Foo< T>.再次,没有来自目标方法的标准,它只能推断出返回类型是Foo< T>的擦除.这是Foo< Object>,它是这样做的.

因此,方法重载解析失败,因为func的任何重载都不与Foo< Object>的实际参数兼容,并且发出错误.

这当然是非常不幸的,如果信息可以简单地从另一个方向流出,从方法的目标回调到呼叫站点,类型可以容易地被推断,并且不会有错误.事实上,Java 8中的编译器可以做到这一点,而且.正如另一个答案所说,这种更丰富的类型推理对于在Java 8中添加的lambdas以及正在使用lambdas的Java API的扩展来说非常有用.

您可以从上述链接下载Java 8 with JSR 335 lambdas的预发行版本.它编译问题中的代码,没有任何警告或错误.

猜你在找的Java相关文章