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父类
}