Java泛型<T extends A<T>>与继承问题咨询
嘿,这种递归自绑定泛型确实容易绕进去——我当初第一次写这种结构的时候也盯着代码愣了半天!先帮你理清楚,然后给你写几个能满足需求的test函数实现。
首先先修正下你代码里的小笔误:sefl()应该是self(),不影响逻辑,但规范点更好。你的类结构是典型的自绑定泛型(用来实现静态多态或者确保子类返回自身类型),现在要写的test函数需要兼容所有B的子类列表,比如List<C>,或者后续你会写的其他B的变种子类列表对吧?
方案1:保留类型信息的泛型方法(推荐)
这个写法能让你在test函数里正常调用self()这类方法,并且保留具体子类的类型:
// 这里的T约束和B类的泛型约束保持一致:T必须是B<T>的子类 public static <T extends B<T>> void test(List<T> list) { for (T item : list) { // 这里调用self()返回的是T类型,完全符合你的类定义约束 T selfInstance = item.self(); // 在这里做你需要的业务操作,比如打印、调用其他方法等 System.out.println("当前实例类型:" + selfInstance.getClass().getSimpleName()); } }
调用的时候直接传List<C>或者其他B的子类列表都没问题:
List<C> cList = new ArrayList<>(); cList.add(new C()); test(cList); // 后续你写的比如D extends B<D>,同样可以传List<D> List<D> dList = new ArrayList<>(); test(dList);
方案2:更宽泛的通配符写法(适合只需要读取元素的场景)
如果你不需要在test里调用子类的泛型方法,只是需要接收任意B及其子类的列表,可以用通配符:
public static void test(List<? extends B<?>> list) { // 这里只能做一些Object级别的操作,比如遍历打印 for (B<?> item : list) { System.out.println("元素类型:" + item.getClass().getSimpleName()); // 如果调用item.self(),返回的是?类型,只能赋值给Object Object self = item.self(); } }
这个写法的优点是更灵活,但缺点是丢失了具体的类型信息,没法直接用子类的强类型方法。
为什么这么写?
你的B类泛型约束是T extends B<T>,这意味着所有合法的B子类都必须满足“自身作为泛型参数传入B”(比如C extends B<C>)。方案1的<T extends B<T>>正好匹配这个约束,确保传入的列表元素都是符合规则的B子类,同时保留类型信息;方案2用? extends B<?>则放宽了约束,允许任何继承自B的类型,哪怕泛型参数不严格匹配(不过实际你的子类都会严格匹配,所以两种方案都能用)。
内容的提问来源于stack exchange,提问作者Matthias Keil
相关产品推荐
相关产品推荐

