泛型方法

1.泛型方法的定义

1
2
3
public <类型参数> 返回类型 方法名(类型参数 变量名) {
...
}

1)只有在方法签名中声明了< T >的方法才是泛型方法,仅使用了泛型类定义的类型参数的方法并不是泛型方法。

public class Test<U> {
    // 该方法只是使用了泛型类定义的类型参数,不是泛型方法
    public void testMethod(U u){
        System.out.println(u);
    }
    // 真正的泛型方法
    public <T> T testMethod1(T t){
        return t;
    }
}

2)泛型方法中可以同时声明多个类型参数

1
2
3
4
5
public class TestMethod<U> {
public <T, S> T testMethod(T t, S s) {
return null;
}
}

☆3)泛型类中定义的类型参数和泛型方法中定义的类型参数是相互独立的,它们一点关系都没有,泛型方法中也可以使用泛型类中定义的泛型参数。

2. 泛型方法的使用

  • 泛型类,在创建类的对象的时候确定类型参数的具体类型;

  • 泛型方法,在调用方法的时候再确定类型参数的具体类型。

泛型方法签名中声明的类型参数只能在该方法里使用,而泛型接口、泛型类中声明的类型参数则可以在整个接口、类中使用

当调用泛型方法时,根据外部传入的实际对象的数据类型,编译器就可以判断出类型参数 T所代表的具体数据类型。

泛型通配符

  • 就是“?”,可以在使用泛型时代表一切类型;
  • 类型通配符是类型实参,而不是类型形参

使用通配符的情形:

  • 例如一个方法定义了< Number >类型,而调用时声明的< Integer >类型(虽然Integer继承Number,所以也没法重写)会报错,这时想支持多种类型,可以用通配符 < ? >;
  • < ? > 定义的 用 Object 类型来接收
1
2
3
public static void show(A<?> B){
Object value = B.getValue();
}

通配符的上限

1
类/接口 <? extends 实参类型>
  • 要求该泛型的类型,只能是实参类型,或实参类型的子类类型;

  • 这里的实参类型就是泛型的类型的上限

如:

1
2
3
4
public static void show(Box<? extends Number> box){
Number value = box.getValue();//类型最大为Number
}

通配符的下限

1
类/接口 <? super 实参类型>

泛型的擦出问题和注意事项

泛型是工作在编译环境里的,一旦程序编译成class文件,class文件中就不存在泛型了,这就是泛型擦除

例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
// 原代码(部分)
ArrayList<String> list =new ArrayList<>();
list.add("java1");
list.add("java2");
String rs = list.get(2);
System.out.println(rs);

// 泛型擦除后
ArrayList list =new ArrayList<>();
list.add("java1");
list.add("java2");
String rs = (String)list.get(2);
System.out.println(rs);

泛型不支持基本数据类型,只支持对象类型(引用数据类型)

如:

1
2
3
4
5
// 错误代码
ArrayList<int> list1=new ArrayList<>();

// 正确代码(Interger类就是在对象中包装了一个基本类型为int的值)
ArrayList<Interger> list1=new ArrayList<>();

好了,到这里,关于泛型的知识就大致地了解了,

再重复一遍泛型的概念:定义类、接口、方法时,同时声明了一个或多个类型变量,称为泛型类、泛型接口、泛型方法,统称为泛型

作用:提供了在编译阶段约束所能操作的数据类型,并自动检查的能力!可以避免强制类型转换。