代码之家  ›  专栏  ›  技术社区  ›  lwi

理解构造函数的有界泛型参数

  •  3
  • lwi  · 技术社区  · 7 年前

    我很困惑,为什么第一个代码片段是编译的,而第二个不是?

    第一个例子

    public class Main {
    
        static Function<B, Integer> f = (b) -> 1;
    
        Main() {
            this(f);
        }
    
        <T extends A> Main(Function<T, Integer> f) {
    
        }
    
    }
    
    class A {    }
    
    class B extends A {    }
    

    public class Main<T extends A> {
    
        static Function<B, Integer> f = (b) -> 1;
    
        Main() {
            this(f);
        }
    
        Main(Function<T, Integer> f) {
    
        }
    
    }
    
    class A {    }
    
    class B extends A {    }
    

    产生错误:

    The constructor Main <T>(Function<B,Integer>) is undefined

    3 回复  |  直到 7 年前
        1
  •  3
  •   davidxxx    7 年前

    在第一个代码中 T 参数的作用域为方法:

    <T extends A> Main(Function<T, Integer> f) {
    
    }
    

    它使用目标的推断(客户端声明的类型返回)来确定 T型
    所以它只能在 Function 是一个 A 或是 尊重 <T extends A> 约束。
    例如,声明这些其他类:

    class B extends A {    }
    
    class C extends A {    }
    
    class D extends B {    }
    

    static Function<B, Integer> fb = (b) -> 1;
    static Function<C, Integer> fc = (b) -> 1;
    static Function<D, Integer> fd = (b) -> 1;
    

    在第二个代码中,您希望通过 Function<B, Integer> 声明的变量 Main 依赖于 类的泛型类型:

    public class Main<T extends A> {
    
        Main(Function<T, Integer> f) {
    
        }
    
    }
    

    问题是这里 T型 可以是 一个 B 或任何其他子类 一个 根据类的客户端使用的泛型类型。
    函数<B,整数> 不可分配给 Function<T, Integer>

        2
  •  3
  •   Sebastian    7 年前

    在第二个例子中,您在类级别引入了类型参数T,但是您将始终使用类B传递一个固定函数。如果你用MainA实例化Main呢?您的代码不是类型安全的。

    在第一个示例中,这不是问题,因为函数上的类型参数只在每次调用时确定。

        3
  •  0
  •   Ondřej Fischer    7 年前

    这些例子不一样。

    示例1-只有构造函数2是泛型的,但构造函数1和类不是。

    所以编译器只需推断constr 1中constr 2的参数类型。这是好的,也是可能的。

    所以编译器已经为constr#1使用了 T extends A T延伸A 不相等 B T 可以是任何其他类 A ).

    与该示例相比,只使用方法(构造函数)类型推断,这在constr#1中完全可以实现。