Java泛型(2)泛型实参的限定
1.官方文档
https://docs.oracle.com/javase/tutorial/java/generics/bounded.html
2.作用
有时候为减少不必要的转换和运行时错误发生。可以对泛型形参使用 extends X 语句,指定泛型实参必需为X及其子类,那么潜在的错误在编译时就可以发现。
- extends X 限定泛型实参为X及其子类型。好处是可以确定调用X的某些行为(函数)一定存在。
- 可以限定一个类类型,多个接口类型,它们之间用 & 相连。
- 类类型必需是第1个
- super 不能用在泛型形参声明时进行限制,如class MyNum<T super Integer>{},super只能用在通配符中进行限制。
- 如有多个泛型形参,每个泛型形参都可以使用extends
3.泛型类中泛型形参 extends
3.1 简单示例
interface I1{} interface I2{} interface I3{} interface I4 extends I2{} @Test public void bounded_test2(){ class A {} abstract class B{} //class C <T extends Number & B > {} //error : 只能有一个类类型 限定 class D <T extends B & I1 & I2 & I3>{} //ok class E <T extends I4 & I2> {} //ok : 接口重复 class F <T extends I1 , I2,无dfo3 > {} //error : 编译通过,但是只限定了I1,多个限定类之间用“&”,其中“,”后面的字符无意义 class G <T extends I1 , K extends A>{} //ok : 多个泛型形参时,可分别extends限定。 }
3.1 使用extends限制的好处示例
public class NaturalNumber<T extends Integer> { private T n; public NaturalNumber(T n) { this.n = n; } public boolean isEven() { return n.intValue() % 2 == 0; } // ... }
T被限制为Integer后,那么第8行的 n.intValue() 调用一定存在。
3.3 extends 泛型类型 及 多类型限制
@Test public void wildcards_test4(){ class MyNumber extends Number implements Serializable,Comparable<MyNumber>{ @Override public int compareTo(MyNumber o) { return this.intValue() - o.intValue(); } @Override public int intValue () { return 0; } @Override public long longValue () { return 0; } @Override public float floatValue () { return 0; } @Override public double doubleValue () { return 0; } } class MyInteger extends Number{ @Override public int intValue () { return 0; } @Override public long longValue () { return 0; } @Override public float floatValue () { return 0; } @Override public double doubleValue () { return 0; } } class MyByte extends Number implements Comparable{ //warning,raw type @Override public int intValue () { return 0; } @Override public long longValue () { return 0; } @Override public float floatValue () { return 0; } @Override public double doubleValue () { return 0; } @Override public int compareTo(Object o) { return 1; } //这里意义,与Object比较 } class MyFloat extends Number implements Comparable<Float>{ //warning,raw type @Override public int intValue () { return 0; } @Override public long longValue () { return 0; } @Override public float floatValue () { return 0; } @Override public double doubleValue () { return 0; } @Override public int compareTo(Float o) { return floatValue() > o ? 1 : (floatValue() == 0 ? 0 : -1); } } //ArrayList<? extends Number & Serializable> ee; //error class A <T extends Number & Serializable & Comparable<?>> {} //ok, class B <T extends Number & Serializable & Comparable<T>> {} //ok class C <T extends Number & Serializable & Comparable > {} //warning,raw type A<MyNumber> am = new A<>(); //A<MyInteger> ai = new A<>(); //error,MyInteger不是Comparable<?> //A<MyByte> ab = new A<>(); //error,MyByte不是Comparable<?> A<MyFloat> af = new A<>(); //B<String> bm = new B<>(); //error String 不是number //B<MyInteger> bi = new B<>(); //error,MyInteger没有实现Comparable<MyInteger> //B<MyFloat> bf = new B<>(); //error,MyFloat没有实现Comparable<MyFloat> //B<MyByte> bb = new B<>(); //error,MyByte实现的是Comparable<MyByte> B<MyNumber> bn = new B<>(); //ok //C<MyInteger> ci = new C<>(); //error,MyInteger没有实现Comparable C<MyByte> cb = new C<>(); //ok C<MyNumber> cn = new C<>(); //ok C<MyFloat> cf = new C<>(); //ok }
4.泛型函数中泛型形参 extends
@Test public void bounded_test3(){ class A implements Comparable<A> { private final int value; public A(int x){ value = x; } public <T extends Number> void foo(T t){ System.out.println("T = " + t.getClass().getSimpleName()); } public <T extends Comparable<T>> int greaterThan(T []array,T x){ int count = 0; for (T t : array){ /*if (t > x){ //error : 只有Number类型和基本类型可以使用 比较运算符 ++count; }*/ if (t.compareTo(x) > 0){ ++count; } } return count; } @Override public int compareTo(A o) { return this.value - o.value; } @Override public String toString() { return "A{" + value + '}'; } } A obj = new A(2); obj.foo(1) ; obj.<Float>foo(1f) ; //obj.<A>foo(obj) ; //error : A 不是 Number的子类。 //obj.foo("str"); ; //error : "str" 不是 Number A [] array = new A[]{new A(1),new A(2),new A(3),new A(4)}; int count = obj.greaterThan(array,obj); System.out.println(String.format("there are %d elements greater than %s",count,obj)); }
其中
- 第11行的greaterThan泛型函数使用了extends语句,限制了泛型实参的类型为Comparable及子类,确保了 compareTo() 比较函数一定存在。
- 第14行编译时会出错,因为只有Number类型和基本类型可以使用 比较运算符。无法确保T一定是Number类型。
运行结果
T = Integer T = Float there are 2 elements greater than A{2}
5.泛型类之间的继承关系
5.1 泛型类型相同,泛型实参不同
泛型类型相同且泛型形参无通配符,泛型实参为继承关系时,它们组成的参数化类型(parameterized type)不为继承关系。
如,Box<Integer>与Box<Number>,Integer是Number的子类,但是Box<Integer>却不是的Box<Number>子类,但都是Object的子类。
示例代码如下:
@Test public void test_inheritance1(){ class A<T> {} class B<T> extends A<T> {} Object object; A<Number> an = new A<>(); B<Integer> bi = new B<>(); //an = bi; //error, object = an; //ok object = bi; //ok }
5.2 泛型实参相同,泛型类型不同
泛型实参相同,继承关系由泛型类型决定。
如Collection<String>,List<String>,ArrayList<String>,泛型实参都是String,这时它们为继承关系。
示例代码如下:
@Test public void test_inheritance2(){ class A<T> {} class B<T> extends A<T> {} Object object; A<Number> an = new A<>(); B<Number> bn = new B<>(); an = bn; //ok object = an; //ok object = bn; //ok }
5.3 多个泛型参形与继承关系
当泛型类型有多个泛型形参时,泛型实参由声明时传给父泛型类型的泛型形参决定。继承关系如上两节.
在 class MyList<T,U> extends ArrayList<T> {} 中,这里声明把第1个泛型形参T传给ArrayList<T>.
详细示例如下:
@Test public void test_inheritance3(){ class MyList<T,U> extends ArrayList<T> {} MyList <String,Number > myList1 = new MyList<>(); MyList <String,Integer> myList2 = new MyList<>(); MyList <Number,Integer> myList3 = new MyList<>(); ArrayList<String > list1 = new ArrayList<>(); ArrayList<Number > list2 = new ArrayList<>(); Object obj ; list1 = myList1 ; //ok , myList1与list1 的泛型实参都是String,因为MyList把第1个泛型实参传给ArrayList<T> list1 = myList2 ; //ok , 泛型实参同是string,且ArrayList是MyList的父类 list2 = myList1 ; //error , 泛型实参不同,泛型类型也不同。 list2 = myList3 ; //ok , 泛型实参同是Number,且ArrayList是MyList的父类 myList1 = myList2 ; //error , 泛型类型相同,但是第2个泛型实参不同,虽然它们为继承关系. obj = list1 ; //ok obj = list2 ; //ok obj = myList1 ; //ok obj = myList2 ; //ok obj = myList3 ; //ok }
6. super 不限制泛型形参
@Test public void bounded_test4(){ //class MyNum <T super Integer>{ } //error : super 不在泛型声明时对泛型形参限制 List<? super Number> ints ; //ok : 与通配符一起使用,限制类型为Number的父类。 ints = new ArrayList<Object>() ; //ok : Object是 Number父类。 //ints = new LinkedList<Integer>() ; //error : Integer 不是 Number父类 }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 【杂谈】分布式事务——高大上的无用知识?