泛型方法

《Java开发技术大全》第10章泛型,本章将介绍泛型的语法和应用,同时展示泛型如何提供类型安全。本节为大家介绍泛型方法。

AD:


10.6 泛型方法

在C++中,除了可以创建模板类,还可以创建模板函数。在Java中也提供了类似的功能:泛型方法。一个方法如果被声明成泛型方法,那么它将拥有一个或多个类型参数,不过与泛型类不同,这些类型参数只能在它所修饰的泛型方法中使用。

创建一个泛型方法常用的形式如下:

[访问权限修饰符] [static] [final] <类型参数列表> 
返回值类型 方法名([形式参数列表])

访问权限修饰符(包括private、public、protected)、static和final都必须写在类型参数列表的前面。

返回值类型必须写在类型参数表的后面。

泛型方法可以写在一个泛型类中,也可以写在一个普通类中。由于在泛型类中的任何方法,本质上都是泛型方法,所以在实际使用中,很少会在泛型类中再用上面的形式来定义泛型方法。

类型参数可以用在方法体中修饰局部变量,也可以用在方法的参数表中,修饰形式参数。

泛型方法可以是实例方法或是静态方法。类型参数可以使用在静态方法中,这是与泛型类的重要区别。

使用一个泛型方法通常有两种形式:

<对象名|类名>.<实际类型>方法名(实际参数表);

和:

[对象名|类名].方法名(实际参数表);

如果泛型方法是实例方法,要使用对象名作为前缀。如果是静态方法,则可以使用对象名或类名作为前缀。如果是在类的内部调用,且采用第二种形式,则前缀都可以省略。

注意到这两种调用方法的差别在于前面是否显示地指定了实际类型。是否要使用实际类型,需要根据泛型方法的声明形式以及调用时的实际情况(就是看编译器能否从实际参数表中获得足够的类型信息)来决定。下面来看一个例子。

【例10.5】 泛型方法使用示例。

//--------------文件名demoGenMethods.java,程序编号10.10-----------
public class demoGenMethods{
//定义泛型方法,有一个形式参数用类型参数T来定义
public static <T> void showGenMsg(T ob, int n){
T localOb = ob; //局部变量也可以用类型参数T来定义
System.out.println(localOb.getClass().getName());
}
public static <T> void showGenMsg(T ob){
System.out.println(ob.getClass().getName()); 
}
public static void main(String args[]){
String str = "parameter";
Integer k = new Integer(123);
//用两种不同的方法调用泛型方法
demoGenMethods.<Integer>showGenMsg(k,1);
showGenMsg(str);
} 
}

程序中定义的两个泛型方法都是静态方法,这在泛型类中是不允许的。而且这两个泛型方法相互重载(参数的个数不同)。在方法体中,类型参数T的使用和泛型类中的使用是相同的。

再来看看如何调用这两个泛型方法:

demoGenMethods.<Integer>showGenMsg(k,1);
showGenMsg(str);
在第一种调用形式中,传入了一个实际类型:<Integer>,它表明类型参数是Integer类型。要注意它的写法,在这种情况下,不能省略作为前缀的类名,也就是不能写成这样:
<Integer>showGenMsg(k,1);

由于传递了一个实际的类型参数Integer,所以编译器知道如何将方法内部的占位符T替换掉。不过需要注意,实际参数k的类型必须也是Integer型,否则编译器会报错。

第二种调用形式明显要简洁一些:

showGenMsg(str);
由于实参str是String类型的,编译器已经有了足够多的信息知道类型参数T是String类型。程序的输出结果如下:
java.lang.Integer
java.lang.String
由于两种形式都能完成任务,而第二种明显要比第一种方便,所以多数情况下会使用第二种方式。不过在某些情况下,实参无法提供足够的类型信息给编译器,那么就需要使用第一种形式。例如:
public <T> void doSomething(){
T ob;
……
}

调用它的时候,根本就没有实际参数,所以编译器无法知道T的实际类型,这种情况下,就必须使用第一种形式。

前面还提到,泛型方法也可以写在泛型类中,比如:

public class Generic<T>{
public <U> void showGenMsg(U ob){
System.out.println(ob.getClass().getName());
}
……
}
这样写当然没有错误,但多数程序员都会将这个泛型方法所需要的类型参数U写到类的头部,即让泛型类带两个参数:
public class Generic<T, U>{
public void showGenMsg(U ob){
System.out.println(ob.getClass().getName());
}
……
}
这样写,类的结构更为清晰。只有一种情况下必须在泛型类中再将方法声明为泛型方法:方法本身是静态的,那就无法像上面那样更改了。
PS: 编译器可以暗示类型参数是什么!即使没有传真实类型参数或实参( 编译器根据实参为我们推断类型参数的值。),但是赋值本身存在暗示。

public class TestExternal {

public static <T> T get(String str){
return (T)str;
}

public static void main(String[] args) {
int str=TestExternal.get("");
}

}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值