Java泛型下限

3

我很清楚地理解上界,但对下界并不完全理解。例如,我有以下代码:

public class Main<T> {
    private T t;

    public Main(T t) {
        this.t = t;
    }

    private static class Base {}

    public static void main(String[] args) {
        Main<? super Base> main = new Main<>(new StringBuilder());
        System.out.println(main.t.getClass());
    }
}

即使 StringBuilder 不是 Base 的超类,为什么在编译时没有错误?我认为提供不相关的类型是非法的(我知道在类型推断后无法将非子类分配给 t),所以我认为会有错误。它也可以与集合一起使用,这是否意味着集合可能存储 Base 的非子类或非超类对象?请不要将我链接到 PECS 问题,我已经阅读过很多。


你需要将你的Main类写成public class Main<T extends Base>。 - Digsb
2
我认为这里的<T>是指Object,它是Base和String的合法超类型。你现在的做法/想法基本上是有缺陷的。请查看此问题的答案(忽略PECS的重复文本):https://dev59.com/52855IYBdhLWcg3wbzxl - markspace
2个回答

2
我将这作为一个实际答案添加。
我认为这里的是Object,它是Base和StringBuilder的合法超类型。你现在做的方法/思考方式是有缺陷的。请查看这个问题的答案(忽略PECS的重复文本): Java中<? super T>和<? extends T>的区别 请注意所接受的答案给出的示例,特别是带有的示例。
List<? super Integer> foo3 = new ArrayList<Integer>();  // Integer is a "superclass" of Integer (in this context)
List<? super Integer> foo3 = new ArrayList<Number>();   // Number is a superclass of Integer
List<? super Integer> foo3 = new ArrayList<Object>();   // Object is a superclass of Integer

由于你允许“钻石操作符”来“计算”T的类型,它会“计算”出Object可以使用并使用它。未经测试,但请检查一下以下代码是否也可以编译通过:
Main<? super Base> main = new Main<Object>(new StringBuilder());

正如我所想,但我不知道如何在运行时检查实际的泛型类型,尽管泛型是擦除类型,但有一些方法可以在运行时获取实际类型,但它们并没有帮助。 - zexed640

2

编辑:我有点晚看到@markspace的答案几乎一样,并且是在此之前发布的。 我只是因为不同的解释风格而将其保留在这里。


这应该是由于钻石操作符<>,由于它,基于最可能的路线进行自动推断,在这种情况下是构造函数参数。

我找不到钻石运算符的官方描述,但各种来源都描述了这种效果-当给定钻石运算符功能时,Java编译器会进行类型推断,确定匹配调用的最合适的构造函数声明

如果您将声明更改为GenericsSuper<?super Base> main = new GenericsSuper<StringBuilder>(new StringBuilder()),则会收到预期的错误。

没有这个明确的声明,<>由于super限制导致<Object>,因此允许任何内容,因为:

  • GenericsSuper中的代码对StringBuilder没有问题。 它只想要T
  • BaseObject中的StringBuilder具有共同的超级。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接