代码之家  ›  专栏  ›  技术社区  ›  Flow Matt McDonald

为什么javac不能用有界类型参数作为返回类型对静态方法的调用位置进行类型检查?[复制]

  •  6
  • Flow Matt McDonald  · 技术社区  · 6 年前

    为什么 javac 在此代码示例中不会因类型错误而中止

    import java.util.List;
    
    public class StaticMethodWithBoundedReturnType {
        static class Foo {
        }
    
        static class Bar extends Foo {
        }
    
        static <F extends Foo> F getFoo(String string) {
            …
        }
    
        public static void main(String[] args) {
            // Compiles without error, even though List does not extend Foo.
            List<Integer> list = getFoo("baz");
        }
    }
    

    显然 List 永远不能是 Foo . 即使存在 列表 会有某种程度的延伸 list 在呼叫地点 getFoo() 爪哇语 可以看出 列表 不满足有界类型约束 extends Foo

    为什么是 爪哇语 不能用有界类型参数作为返回类型的静态方法的调用位置进行类型检查?

    看来我可以通过以下稍微的修改来获得类型安全性:

    import java.util.List;
    
    public class StaticMethodWithBoundedReturnType {
        static class Foo {
        }
    
        static class Bar extends Foo {
        }
    
        static <F extends Foo> F getFoo(String string, Class<F> clazz) {
            …
        }
    
        public static void main(String[] args) {
            // Does not compile \o/
            List<Integer> list = getFoo("baz", List.class);
        }
    }
    

    Class getFoo()的参数,该参数根本没有在方法的主体中使用。有没有更好的方法来实现类型安全?

    1 回复  |  直到 6 年前
        1
  •  2
  •   Stephen C    6 年前

    要理解这一点,我们需要理解以下实际含义:

    static <F extends Foo> F getFoo(String string) {
        return null;
    }
    

    getFoo 返回某种类型的值,该值必须从调用所在的上下文中推断。此外,它还设置了一个约束,即推断的类型必须是 Foo .

    因为 null

    为了说明这一点,请尝试以下变体:

    import java.util.List;
    
    public class StaticMethodWithBoundedReturnType {
        static class Foo {
        }
    
        static class Bar extends Foo {
        }
    
        static <F extends Foo> F getFoo(String string) {
            return new Bar();
        }
    
        public static void main(String[] args) {
            // Compiles without error, even though List does not extend Foo.
            List<Integer> list = getFoo("baz");
        }
    }
    

    这会产生编译错误

    StaticMethodWithBoundedReturnType.java:11: error: incompatible types:
    Bar cannot be converted to F
            return new Bar();
                   ^
    

    为什么Bar和F不兼容?

    回答:因为 F ( R & ? extends Foo ) 哪里 R 结果的类型 格福 分配给。而且,在 格福 R 将。(事实上,它可以有很多不同的类型!)

        <F extends Foo> F getFoo(String string)
    

    有问题。但是,请考虑:

    static <F extends Foo> F getFoo(Class<F> clazz) {
        return class.newInstance();
    }
    

    这是合法的,并将返回一个满足运行时类型安全(本地)的值。但你会的 然后 如果尝试将其分配给 List<Integer> :

    StaticMethodWithBoundedReturnType.java:16: error: incompatible types:
    inference variable F has incompatible bounds
            List<Integer> list = getFoo(Bar.class);
                                       ^
        equality constraints: Bar
        upper bounds: List<Integer>,Foo
      where F is a type-variable:
        F extends Foo declared in method <F>getFoo(Class<F>)
    1 error
    

     List<Integer> list = getFoo("baz");
    

    这是合法的因为 结果的类型是交集类型 (List<Integer> & ? extends Foo) . 实际上,这种交集类型是可实现的;例如

     class Baz extends Bar implements List<Integer> { /* list methods */ }
    

    (事实上在这方面没有实施 Baz 在我们的课程中上课是无关紧要的。可能有一个。)

    list 将被分配 无效的 ,这不是运行时类型冲突。