java 泛型
泛型的作用:在编译阶段检测非法的类型
泛型的本质:参数化类型,将数据类型指定为参数。
何时使用泛型?
普通的java方法能够接受的参数类型是被预先定义、固定类型的。
如果我们要调用同一个方法(相同方法名)但需要传入不同类型参数时就需要用到方法的重载,但重载需要为每一种可能的参数类型都重新编写一个方法。如果需要传入多种参数类型,这会大大增加开发工作量。
此时就可以通过泛型这个工具来将方法的参数类型 也 参数化,使方法能够动态的接受不同类型的参数,这样就无需再写多个重载的方法,大大减少了代码量。
根据传递给泛型方法的参数类型,编译器适当地处理每一个方法调用。泛型方法是面向编译器的
定义泛型方法的规则:
1.类型参数声明(由尖括号<>分隔),类型参数声明 应放置在 方法返回类型声明 之前
2.每一个 类型参数声明 包含一个或多个 类型参数(又称类型变量),参数间用逗号隔开。
3.类型参数 可以作为 返回值类型声明,能作为泛型方法得到的实际参数类型的占位符。
4.泛型方法体的声明和其他方法一样,类型参数只能传入引用型类型,不能是原始类型。
示例:
public class GenericMethodTest {
public static < E > void printArray( E[] inputArray ) {
for ( E element : inputArray ){
System.out.printf( "%s ", element );
}
System.out.println();
}
}
示例:
有界的类型参数:
按照普通定义的泛型方法可接受所有类型的 参数, 当我们需要限定传入的参数类型范围时怎么办?如:在某个场景我只需要接收Number或者Number子类实例。这时我们的大神JDK设计师们就提供了 有界类型参数 来满足这种需求。
定义方法:
在 类型参数名称 后加上 extends(不能是implements) 接限定类型的上界。
示例:
public class MaximumTest{
public static <T extends Comparable<T>> T maximum(T x, T y, T z) {
T max = x; // 假设x是初始最大值
if ( y.compareTo( max ) > 0 ){
max = y; //y 更大
}
if ( z.compareTo( max ) > 0 ){
max = z; // 现在 z 更大
}
return max; // 返回最大对象
}
public static void main( String args[] ) {
System.out.printf( "%d, %d 和 %d 中最大的数为 %d ",
3, 4, 5, maximum( 3, 4, 5 ) );
System.out.printf( "%.1f, %.1f 和 %.1f 中最大的数为 %.1f ",
6.6, 8.8, 7.7, maximum( 6.6, 8.8, 7.7 ) );
System.out.printf( "%s, %s 和 %s 中最大的数为 %s ","pear",
"apple", "orange", maximum( "pear", "apple", "orange" ) );
}
}
泛型类:
如果我们需要在一个类中定义动态的属性的类型,则可以使用泛型类。
泛型类定义:
在类名后接<类型变量1, 类型变量2, 类型变量3,..>
泛型类声明:
类目<具体类型1,具体类型2,具体类型3,...>
示例:
public class Box<F> {
private F f;
public F getF() {
return f;
}
public void setF(F f) {
this.f = f;
}
public static void main(String[] args) {
Box<Double> doubleBox = new Box<>();
Box<Class> classBox = new Box<>();
doubleBox.setF(3.1415926);
classBox.setF(Class.class);
System.out.printf("浮点数为:%f
", doubleBox.getF());
System.out.printf("类为:%s
", classBox.getF());
}
}
类型通配符: ?
用?代替具体的类型参数,代表允许传入任何类型的类型
public static void getData(List<?> data) {
System.out.println("data :" + data.get(0));
}
类型通配符与不加通配符有何区别?
不加类型通配符的方法,在方法体里可对未限定类型进行任何数据类型的操作。
而加上类型通配符之后,因为不确定将传入何种类型,及被限定为“任意类型”的值,反而不能使用任意类型的数据进行操作。
如:
public static void getData(List data) {
data.add(1);
}
是正确的。
而
public static void getData(List<?> data) {
data.add(1);
}
会编译报错。
即使是
public static void getData(List<? extends Integer> data) {
data.add(1);
}
也无法通过编译。
通配符上限: ? extends 上限类型
public static void getData(List<? extends Number> data) {
System.out.println("data :" + data.get(0));
}
通配符下限: ? super Number
public static void getData(List<? super Number> data) {//表示只能接受Number及其父类类型
System.out.println("data :" + data.get(0));
}