在java中,泛型分为泛型类、泛型接口、泛型方法。
其中泛型类、泛型接口理解较为容易,但是泛型方法,容易让人产生困惑。
那么我们来学习一下泛型方法。
泛型方法,是在调用方法的时候指明泛型的具体类型 。
/**
- 泛型方法的基本介绍
- @param列表中的 Class< T > tClass 这里T是传入的泛型类型实参,一般可以是Integer, Object等包装类型或者自定义类型,tClass 是类型 T的一个形参对象
- @return T 返回值为T类型
- 说明:
1)”修饰符“ 与 “返回值类型” 之间的 < T > 为声明此方法为泛型方法。只有声明了< T >的方法才是泛型方法,泛型类中的使用了泛型的成员方法并不是泛型方法。
2)< T >是告诉编译器,当前的方法的值传入类型可以和类初始化的泛型类不同,也就是该方法的泛型类可以自定义,不需要跟类初始化的泛型类相同(如果泛型方法在泛型类之中)。当然即使不是泛型类,也可以声明泛型方法。
3)< T >表明该方法将使用泛型类型 T,此时才可以在参数列表、返回类型中使用泛型类型T。
4)与泛型类的定义一样,此处< T >中的 字母T 可以随便写为任意标识,常见的如 ?、T、E、K、V等形式的参数常用于表示泛型。
? 是一个关键词,它在此处是通配符,表示不确定的java类型, 类似Object,表明这个类型可以是任意类型。
以下T、E、K、V则不是关键词,仅仅是有一些习惯上的约定,事实上用其它字母代替也行:
T 表示java类型。
K, V 分别代表java键值中的Key Value。
E 代表Element。
*/
修饰符 <T,E> 返回值类型 myMethod_1(Class<T> tClass, Class<E> eClass) {
T instance_t = tClass.newInstance();
E instance_e = eClass.newInstance();
...
...
return xxx; //返回与“返回值类型” 匹配的对象
}
修饰符 <E> 返回值类型 myMethod_2(E para){
System.out.println(para.toString());
...
...
return xxx; //返回与“返回值类型” 匹配的对象
}
修饰符 <E> E myMethod_2_1(E para){
System.out.println(para.toString());
...
...
return para; //返回与“返回值类型” E 匹配的对象
}
修饰符 <E> E myMethod_3() {
...
...
return xxx; //返回与“返回值类型” E 匹配的对象
}
myMethod_1和myMethod_2中,声明了类型< T >或者 <T,E>,然后在参数中使用来类型T 、类型E的形参。
举例如下:
public <E> boolean myMethod_2(E para){
...
return false;
}
public <E> void myMethod_2(E para){
...
return;
}
public <E> E myMethod_2(E para){
...
return para;
}
public <T> T[] toArray(T[] a) {//参数列表使用了T类型数组T[], 返回值也使用了T类型数组T[]
if (a.length < size)
// Make a new array of a's runtime type, but my contents:
return (T[]) Arrays.copyOf(elementData, size, a.getClass());
System.arraycopy(elementData, 0, a, 0, size);
if (a.length > size)
a[size] = null;
return a;
}
myMethod_3中,声明了类型< E >,方法参数列表中没有类型 E的形参,但是返回值是使用了类型E。
对myMethod_3举例如下:
static <E> E elementAt(Object[] es, int index) {//参数列表中没有使用类型E的形参
return (E) es[index]; //返回值使用了E类型,使用了(E)类型强转
}
从上面的例子我们可以看到,泛型方法在声明时,
1、要么在方法的参数列表中使用了< T >或者 <T,E>声明的的类型,
2、要么就是在返回值使用了< T >声明的类型,
3、要么就是在参数列表、返回值都使用了< T >声明的类型。
在myMethod_1中,我们使用了形参对象的newInstance()来创建新的对象,
T instance_t = tClass.newInstance();
E instance_e = eClass.newInstance();
在泛型方法中,我们不知道形参传递来的具体的类型是什么,也不知道形参的构造方法如何,因此没有办法为它去new一个新对象,假如我们只需要使用传递进来的形参对象,自然不需要创建新的对象,
但某些情况下,我们可能需要创建新的对象来使用,这个时候可以利用变量tClass对象的的newInstance方法去创建新对象,也就是利用反射创建对象。
在最后,我们来看一个泛型的声明形式,看看它有什么问题:
public static <M> void tst1(){
System.out.println("this is test 1");
return;
}
声明为了泛型方法,但是方法入参、返回值都没有使用类型M,虽然编译并不会报错,
调用该方法也能正常运行,但是这样的声明是毫无意义的。
参考:package java.util.ArrayList.java