当前位置: 首页 > news >正文

什么是 Java 泛型的上下界限定符?

Java 泛型的上下界限定符

Java 泛型的上下界限定符用于限制类型参数的范围,确保类型参数满足特定的约束条件。主要包括上界限定符(extends)和下界限定符(super)。

一、上界限定符(Upper Bounded)

1. 基本语法

<TextendsSomeClass>// 限制为某个类或其子类<TextendsSomeInterface>// 限制为实现了某个接口<TextendsClass&Interface1&Interface2>// 多重限定

2. 单个上界

// 限制 T 必须是 Number 或其子类publicclassNumberBox<TextendsNumber>{privateTvalue;publicTgetValue(){returnvalue;}// 可以调用 Number 的方法publicdoubledoubleValue(){returnvalue.doubleValue();// Number 类的方法}}// 使用示例NumberBox<Integer>intBox=newNumberBox<>();// ✅ Integer 是 Number 的子类NumberBox<Double>doubleBox=newNumberBox<>();// ✅ Double 是 Number 的子类NumberBox<String>stringBox=newNumberBox<>();// ❌ String 不是 Number 的子类

3. 多个上界(多重限定)

// T 必须同时是 Number 的子类并实现 Comparable 接口publicclassComparableNumber<TextendsNumber&Comparable<T>>{privateTvalue;publicTmax(Tother){returnvalue.compareTo(other)>0?value:other;}}// 使用示例ComparableNumber<Integer>cn=newComparableNumber<>();// ✅// Integer 是 Number 的子类,且实现了 Comparable<Integer>

注意:多重限定中,类类型必须放在第一个位置,且只能有一个类类型(可以有多个接口)。

// ✅ 正确<TextendsNumber&Comparable<T>&Serializable>// ❌ 错误:类类型不在第一个位置<TextendsComparable<T>&Number>// ❌ 错误:多个类类型<TextendsNumber&Integer>

4. 通配符上界

publicclassWildcardExample{// ? extends Number 表示可以接受 Number 或其子类publicstaticvoidprocessNumbers(List<?extendsNumber>list){for(Numbernum:list){System.out.println(num.doubleValue());}}publicstaticvoidmain(String[]args){List<Integer>intList=Arrays.asList(1,2,3);List<Double>doubleList=Arrays.asList(1.5,2.5,3.5);List<String>stringList=Arrays.asList("a","b","c");processNumbers(intList);// ✅processNumbers(doubleList);// ✅processNumbers(stringList);// ❌}}

重要特性:使用? extends时,只能读取,不能写入(除了 null)。

publicstaticvoidreadOnlyExample(List<?extendsNumber>list){// ✅ 可以读取Numbernum=list.get(0);// ❌ 不能写入(除了 null)// list.add(1); // 编译错误// list.add(1.5); // 编译错误list.add(null);// ✅ null 是任何类型的子类}

二、下界限定符(Lower Bounded)

1. 基本语法

<?superSomeClass>// 限制为某个类或其父类

2. 通配符下界

publicclassLowerBoundExample{// ? super Integer 表示可以接受 Integer 或其父类publicstaticvoidaddNumbers(List<?superInteger>list){list.add(1);// ✅ Integerlist.add(2);// ✅ Integerlist.add(null);// ✅ null}publicstaticvoidmain(String[]args){List<Integer>intList=newArrayList<>();List<Number>numberList=newArrayList<>();List<Object>objectList=newArrayList<>();List<Double>doubleList=newArrayList<>();addNumbers(intList);// ✅addNumbers(numberList);// ✅addNumbers(objectList);// ✅addNumbers(doubleList);// ❌ Double 不是 Integer 的父类}}

重要特性:使用? super时,可以写入,但读取受限

publicstaticvoidwriteOnlyExample(List<?superInteger>list){// ✅ 可以写入 Integer 或其子类list.add(1);list.add(2);// ⚠️ 读取时只能当作 Object 使用Objectobj=list.get(0);// ✅// Integer num = list.get(0); // ❌ 编译错误}

三、PECS 原则

PECS=ProducerExtends,ConsumerSuper

这是一个重要的设计原则:

  • Producer(生产者):提供数据,使用? extends
  • Consumer(消费者):消费数据,使用? super
importjava.util.*;publicclassPECSExample{// Producer: 只从集合中读取数据publicstaticdoublesum(List<?extendsNumber>list){doubletotal=0;for(Numbernum:list){total+=num.doubleValue();// 只读取}returntotal;}// Consumer: 只向集合中写入数据publicstaticvoidaddAll(List<?superInteger>dest,List<Integer>src){for(Integernum:src){dest.add(num);// 只写入}}// 既是 Producer 又是 Consumer:不使用通配符publicstaticvoidcopy(List<Integer>dest,List<Integer>src){for(Integernum:src){dest.add(num);}}publicstaticvoidmain(String[]args){List<Integer>intList=Arrays.asList(1,2,3);List<Double>doubleList=Arrays.asList(1.5,2.5,3.5);// ProducerSystem.out.println("Sum of ints: "+sum(intList));System.out.println("Sum of doubles: "+sum(doubleList));// ConsumerList<Number>numberList=newArrayList<>();addAll(numberList,intList);System.out.println("Number list: "+numberList);}}

四、无界通配符

1. 基本语法

<?>// 表示未知类型,等价于 <? extends Object>

2. 使用场景

publicclassUnboundedWildcard{// 当你只关心集合本身,而不关心元素类型时publicstaticbooleanisEmpty(List<?>list){returnlist.isEmpty();}publicstaticintsize(List<?>list){returnlist.size();}// 清空集合publicstaticvoidclear(List<?>list){list.clear();}publicstaticvoidmain(String[]args){List<String>stringList=Arrays.asList("a","b","c");List<Integer>intList=Arrays.asList(1,2,3);System.out.println("String list size: "+size(stringList));System.out.println("Int list size: "+size(intList));}}

注意:使用<?>时,不能写入任何非 null 的值

publicstaticvoidunboundedExample(List<?>list){// ✅ 可以读取,但只能当作 ObjectObjectobj=list.get(0);// ❌ 不能写入(除了 null)// list.add("hello"); // 编译错误// list.add(1); // 编译错误list.add(null);// ✅}

五、综合示例

importjava.util.*;publicclassGenericBoundsExample{// 上界:只能读取publicstaticvoidprintNumbers(List<?extendsNumber>list){System.out.print("Numbers: ");for(Numbernum:list){System.out.print(num.doubleValue()+" ");}System.out.println();}// 下界:只能写入publicstaticvoidaddIntegers(List<?superInteger>list){list.add(10);list.add(20);list.add(30);}// 泛型方法的上界publicstatic<TextendsComparable<T>>Tmax(List<T>list){if(list.isEmpty()){thrownewIllegalArgumentException("Empty list");}Tmax=list.get(0);for(Titem:list){if(item.compareTo(max)>0){max=item;}}returnmax;}// 多重限定publicstatic<TextendsNumber&Comparable<T>>TmaxNumber(List<T>list){if(list.isEmpty()){thrownewIllegalArgumentException("Empty list");}Tmax=list.get(0);for(Titem:list){if(item.compareTo(max)>0){max=item;}}returnmax;}publicstaticvoidmain(String[]args){// 上界示例List<Integer>ints=Arrays.asList(1,2,3,4,5);List<Double>doubles=Arrays.asList(1.1,2.2,3.3);printNumbers(ints);// ✅printNumbers(doubles);// ✅// 下界示例List<Number>numbers=newArrayList<>();addIntegers(numbers);System.out.println("Numbers after adding: "+numbers);// 泛型方法示例List<String>strings=Arrays.asList("apple","banana","cherry");System.out.println("Max string: "+max(strings));List<Integer>moreInts=Arrays.asList(5,2,8,1,9);System.out.println("Max number: "+maxNumber(moreInts));}}

六、上下界对比总结

特性<? extends T>(上界)<? super T>(下界)<?>(无界)
读取✅ 可以读取为 T⚠️ 只能读取为 Object⚠️ 只能读取为 Object
写入❌ 不能写入(除 null)✅ 可以写入 T 及其子类❌ 不能写入(除 null)
用途Producer(生产者)Consumer(消费者)只关心集合本身
灵活性限制为 T 及其子类限制为 T 及其父类任意类型

七、实际应用场景

1. Collections.copy()

// JDK 源码中的实现publicstatic<T>voidcopy(List<?superT>dest,List<?extendsT>src){// dest 是 Consumer,使用 super// src 是 Producer,使用 extends}

2. Collections.max()

// JDK 源码中的实现publicstatic<TextendsObject&Comparable<?superT>>Tmax(Collection<?extendsT>coll){// T 必须实现 Comparable// 集合元素必须是 T 或其子类}

3. 自定义工具类

publicclassCollectionUtils{// 将源集合的所有元素添加到目标集合publicstatic<T>voidaddAll(Collection<?superT>target,Collection<?extendsT>source){target.addAll(source);}// 查找集合中的最大元素publicstatic<TextendsComparable<?superT>>Tmax(Collection<?extendsT>coll){Iterator<?extendsT>i=coll.iterator();Tmax=i.next();while(i.hasNext()){Tnext=i.next();if(next.compareTo(max)>0){max=next;}}returnmax;}}

总结

  • 上界extends:限制类型参数为某个类或其子类,用于生产者场景,只能读取
  • 下界super:限制类型参数为某个类或其父类,用于消费者场景,可以写入
  • PECS 原则:Producer Extends,Consumer Super
  • 无界通配符?:表示未知类型,只能读取为 Object,不能写入
  • 多重限定:可以同时指定类和多个接口,但类必须放在第一位

理解上下界限定符对于编写灵活、类型安全的泛型代码至关重要!

http://www.jsqmd.com/news/397192/

相关文章:

  • Java 泛型擦除是什么?
  • 表情包制作(ai banana使用教程)
  • 题解:洛谷 P1962 斐波那契数列
  • Solution - P2175 小Z的游戏分队
  • 北京丰宝斋上门回收,名家字画+古木家具,一站式变现更省心 - 品牌排行榜单
  • 题解:洛谷 P4071 [SDOI2016] 排列计数
  • 北京明清古籍回收,丰宝斋老字号上门,现金结算,价公道有保障 - 品牌排行榜单
  • [Kaleidoscope of Physics] 自然坐标系
  • 2026 专业除醛产品怎么选:光触媒和生物酶睿石适配场景 + 组合技巧 - 资讯焦点
  • 2026年2月中国推荐GEO服务商TOP8综合实力权威榜单:企业AISEO选型深度指南 - 资讯焦点
  • 北京线装书回收,丰宝斋上门鉴定,现金结算,专业守护文脉 - 品牌排行榜单
  • MISSION.md — AI自主创收作战手册
  • 2026年正规靠谱十大移民中介公司推荐,零拒签+零纠纷是选择金标准 - 资讯焦点
  • 2026年2月中国正规移民中介十大排行榜:飞际移民位居前列的客观观察 - 资讯焦点
  • 北京老书旧书回收,丰宝斋上门服务,现金结算,不让老书蒙尘 - 品牌排行榜单
  • 2026年智能干选机行业主流制造商权威评测:技术落地成核心分水岭,头部格局基本成型 - 资讯焦点
  • 题解:洛谷 P1313 [NOIP 2011 提高组] 计算系数
  • 北京红宝书回收,丰宝斋上门服务,现金结算,价高同行 - 品牌排行榜单
  • 2026年2月权威发布:GEO优化服务商排行TOP7综合实力评估与选型指南 - 资讯焦点
  • 长期主义的拼命,会给你留后劲
  • 京东e卡回收灵活渠道解析 - 资讯焦点
  • 新房+儿童房+新车除醛攻略:2026 三款顶级除醛产品组合使用方法 - 资讯焦点
  • 北京丰宝斋上门回收名家字画,当场现金结算,老字号更靠谱 - 品牌排行榜单
  • 头屑反复、头皮瘙痒?2026实测5款高口碑去屑洗发水,重拾清爽秀发 - 资讯焦点
  • 最新实测|头油星人必看!10款热门控油洗发水深度测评,告别扁塌大油头 - 资讯焦点
  • 国产2026防脱发生发增发密发哪个牌子效果好?十大高分防脱生发品牌排行榜 - 资讯焦点
  • 1978-2024年各地级市全要素生产率数据
  • 在机器学习建模过程中,参数调优是个绕不开的坎。今天咱们用Matlab的神经网络工具箱实战一把K折交叉验证寻参,手把手搞定隐藏层节点数的选择
  • 两座城市,同一个 “立方”:透视春晚舞台上的中国算力地标 - 资讯焦点
  • 【硬核推测】2026自动挡古筝技术细节全解析|从乐展线索反推量产方案,附工程落地猜想