10.6 泛型接口
10.6.1 定义泛型接口
在JDK1.5之后,不仅可以声明泛型类,也可以声明泛型接口。 声明泛型接口和声明泛型类的语法类似,也就是在接口名称后面加上泛型标识 <T>。 格式如下所示:
泛型接口定义格式:
[访问权限] 接口名称<泛型标识>{
}
定义一个泛型接口如下:
interface Info<T>{
public T getVar();
}
10.6.2 泛型接口的两种实现方式
泛型接口定义完成之后,就要定义此接口的子类,定义泛型接口的子类有两种方式:
- 直接在子类后声明泛型
- 直接在子类实现的接口中明确地给出泛型类型
在子类的定义上声明泛型类型:
interface Info<T>{
public T getVar();
}
class InfoImpl<T> implements Info<T>{
private T var;
public InfoImpl(T var){
this.var = var;
}
public void setVar(T var){
this.var = var;
}
public T getVar(){ //覆写接口中的抽象方法
return var;
}
}
public class GenericsDemo17{
public static void main(String args[]){
Info<String> i = null; //定义接口对象
i = new InfoImpl<String>("forfan06");
System.out.println("内容:" + i.getVar());
}
}
泛型接口的子类在实现接口时,直接在实现的接口处指定了具体的泛型类型。在覆写接口的方法时直接指定类型。
interface Info<T>{
public T getVar();
}
class InfoImpl implements Info<String>{
private String var;
public InfoImpl(String var){
this.var = var;
}
public void setVar(String var){
this.var = var;
}
public String getVar(){ //覆写接口中的抽象方法
return var;
}
}
public class GenericsDemo18{
public static void main(String args[]){
Info<String> i = null; //定义接口对象
i = new InfoImpl("forfan06");
System.out.println("内容:" + i.getVar());
}
}
10.7 泛型方法
前面讲到泛型操作是将整个类进行泛型化,同样,也可以在类中定义泛型化的方法。泛型方法的定义与其所在的类是否是泛型类没有任何关系,所在的类可以是泛型类也可以不是泛型类。
10.7.1 定义泛型方法
在泛型方法中可以定义泛型参数,此时,参数的类型就是传入数据的类型。 定义泛型方法的格式:
<span style="font-size:14px;"><strong>[访问权限] <泛型标识> 泛型标识 方法名称([泛型标识 参数名称])
//个人表示比较倾向于下面的格式
[访问权限] <泛型标识> 泛型标识 返回值类型 方法名称([泛型标识 参数名称])</strong></span>
范例:定义一个泛型方法
class Demo{
public <T> T fun(T t){
return t;
}
}
public class GenericsDemo19{
public static void main(String args[]){
Demo d = new Demo();
String str = d.fun("forfan06");
int i = d.fun(27);
System.out.println(str);
System.out.println(i);
}
}
10.7.2 通过泛型方法返回泛型类实例
如果可以通过泛型方法返回一个泛型类的实例化对象,则必须在方法的返回类型声明处明确地制定泛型标识!!!!!
范例:通过方法返回泛型类实例
class Info<T extends Number>{
private T var;
public T getVar(){
return var;
}
public void setVar(T var){
this.var = var;
}
public String toString(){
return this.var.toString();
}
}
public class GenericsDemo20{
public static void main(String args[]){
Info<Integer> i = fun(28); //传递整数到fun()方法
System.out.println(i.getVar());
Info<Float> f = fun(27.2f);
System.out.println(f.getVar());
}
//<span style="color:#ff0000;"><u>此方法在static处定义了“<T extends Number>”, 表示方法中传入或返回的泛型类型由调用方法时所设置的参数类型决定</u></span>
public static <T extends Number> Info<T> fun(T param){
Info<T> temp = new Info<T>(); //根据传入的数据类型实例化Info对象
temp.setVar(param); //将传递的内容设置到Info类的var属性中
return temp; //返回实例化对象
}
}
10.7.3 使用泛型统一传入的参数类型
一个方法要求传入的泛型对象的泛型类型一致,也可以通过泛型方法指定。
class Info<T>{
private T var;
public void setVar(T var){
this.var = var;
}
public T getVar(){
return var;
}
public String toString(){
return var.toString();
}
}
public class GenericsDemo21{
public static void main(String args[]){
Info<String> i1 = new Info<String>();
Info<String> i2 = new Info<String>();
i1.setVar("forfan06");
i2.setVar("你好");
add(i1, i2); //此语句编译可以通过,并且可以正常运行
Info<Integer> i3 = new Info<Integer>();
i3.setVar(27);
<del><span style="color:#ff0000;"> add(i1, i3); //此时编译出错:</span></del>
}
public static <T> void add(Info<T> i1, Info<T> i2){
System.out.println(i1.getVar() + ", " + i2.getVar());
}
}
add(i1, i3)语句编译出错:
GenericsDemo21.java:22: error: method add in class GenericsDemo21 cannot be applied to given types;
add(i1, i3);
^
required: Info,Info
found: Info,Info
reason: no instance(s) of type variable(s) T exist so that argument type Info conforms to formal parameter type Info
where T is a type-variable:
T extends Object declared in method add(Info,Info)
1 error
使用此种方法可以为程序操作的安全性提供保障
10.8 泛型数组
使用泛型方法时,可以传递或返回一个泛型数组。如下面程序:
public class GenericsDemo22{
public static void main(String args[]){
Integer i[] = fun1(1, 2, 3, 4, 5, 6); //返回泛型数组
fun2(i); //输出数组内容
}
public static <T> T[] fun1(T...arg){ //接收可变参数,返回泛型数组
return arg; //返回泛型数组
}
public static <T> void fun2(T param[]){ //接收泛型数组
System.out.println("接收泛型数组:");
for (T t:param){ //java中新特性foreach功能
System.out.print(t + "、");
}
System.out.println();
}
}
正常运行,但是有以下警告: 此警告之前有讲到过原因以及解决方法
GenericsDemo22.java uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.
10.9 泛型的嵌套设置
可以在一个类的泛型中指定另外一个类的泛型。
范例:定义两个泛型类 & 设置嵌套泛型
class Info<K, V>{
private K key;
private V value;
public Info(K key, V value){
this.setKey(key);
this.setValue(value);
}
public K getKey(){
return key;
}
public V getValue(){
return value;
}
public void setKey(K key){
this.key = key;
}
public void setValue(V value){
this.value = value;
}
}
class Demo<S>{
private S info;
public Demo(S info){
this.setInfo(info);
}
public S getInfo(){
return info;
}
public void setInfo(S info){
this.info = info;
}
}
//测试类
public class GenericsDemo23{
public static void main(String args[]){
Info<String, Integer> info = new Info<String, Integer>("forfan06", 27);
Demo<Info<String, Integer>> demo = new Demo<Info<String, Integer>>(info);
System.out.println(demo.getInfo().getKey() + ", " + demo.getInfo().getValue());
}
}
10.10 范例 --- 泛型应用
用户在设计类时往往会使用类的关联关系。 例如, 一个人中可以定义一个信息的属性,但是一个人有各种各样的信息(联系方式、基本信息等等),此时信息属性的类型是不确定的。所以可以通过泛型进行声明,然后只要设计相应的信息类即可。
- 定义标识接口 没有定义任何方法的接口,一般称为标识接口!!!
interface Info{ /定义一个标识接口, 此接口没有定义任何抽象方法
}
- 定义表示信息的类 --- 联系方式,此类实现Info接口
class Contact implements Info{ //实现Info接口
private String address;
private String telphone;
private String zipcode;
public Contact(String address, String telphone, String zipcode){
this.setAddress(address);
this.setTelphone(telphone);
this.setZipcode(zipcode);
}
public String getAddress(){
return address;
}
public String getTelphone(){
return telphone;
}
public String getZipcode(){
return zipcode;
}
public void setAddress(String address){
this.address = address;
}
public void setTelphone(String telphone){
this.telphone = telphone;
}
public void setZipcode(String zipcode){
this.zipcode = zipcode;
}
public String toString(){
return "联系方式:\n" + "\t|-联系电话:" + this.telphone + "\t|-联系地址:" + this.address + "\t邮政编码:" + this.zipcode; //返回对象信息
}
}
- 定义表示信息的类 --- 个人基本信息,此类实现Info接口
class Introduction implements Info{ //实现Info接口
private String name;
private String sex;
private int age;
public Introduction(String name, String sex, int age){
this.setName(name);
this.setSex(sex);
this.setAge(age);
}
public String getName(){
return name;
}
public String getSex(){
return sex;
}
public int getAge(){
return age;
}
public void setName(String name){
this.name = name;
}
public void setSex(String sex){
this.sex = sex;
}
public void setAge(int age){
this.age = age;
}
public String toString(){
return "基本信息:\n" + "\t|-姓名:" + this.name + "\t|-性别:" + this.sex + "\t年龄:" + this.age; //返回对象信息
}
}
- 定义Person类,Person类中的info属性的类型使用泛型
class Person<T extends Info>{ //此处指定了上限,必须是Info接口的子类
private T info;
public Person(T info){
this.setInfo(info);
}
public T getInfo(){
return info;
}
public void setInfo(T info){
this.info = info;
}
public String toString(){
return info.toString();
}
}
此时Person类中info属性并没有指定具体类型,此类型由程序外部决定,但是必须是Info接口的子类。
- 测试类:
public class GenericsDemo24{
public static void main(String args[]){
Person<Contact> per1 = new Person<Contact>(new Contact("上海市", "136****xxxx", "021"));
System.out.println(per1);
Person<Introduction> per2 = new Person<Introduction>(new Introduction("forfan06", "male", 27));
System.out.println(per2);
}
}
- 运行结果:
-------------------------------------------------
联系方式如下:
联系电话:136****xxxx, 联系地址:上海市, 邮政编码021
个人信息如下:
姓名:forfan06, 性别:male, 年龄:27
-------------------------------------------------
整体程序代码如下:
interface Info{ //定义一个标识接口,此接口没有定义任何抽象方法
}
class Contact implements Info{ //实现Info接口
private String address;
private String telphone;
private String zipcode;
public Contact(String address, String telphone, String zipcode){
this.setAddress(address);
this.setTelphone(telphone);
this.setZipcode(zipcode);
}
public String getAddress(){
return address;
}
public String getTelphone(){
return telphone;
}
public String getZipcode(){
return zipcode;
}
public void setAddress(String address){
this.address = address;
}
public void setTelphone(String telphone){
this.telphone = telphone;
}
public void setZipcode(String zipcode){
this.zipcode = zipcode;
}
public String toString(){
return "联系方式如下:\n" +
"联系电话:" + this.telphone +
", 联系地址:" + this.address +
", 邮政编码" + this.zipcode;//返回对象信息
}
}
class Introduction implements Info{ //实现Info接口
private String name;
private String sex;
private int age;
public Introduction(String name, String sex, int age){
this.setName(name);
this.setSex(sex);
this.setAge(age);
}
public String getName(){
return name;
}
public String getSex(){
return sex;
}
public int getAge(){
return age;
}
public void setName(String name){
this.name = name;
}
public void setSex(String sex){
this.sex = sex;
}
public void setAge(int age){
this.age = age;
}
public String toString(){
return "个人信息如下:\n" +
"姓名:" + this.name +
", 性别:" + this.sex +
", 年龄:" + this.age;//返回对象信息
}
}
class Person<T extends Info>{ //此处指定了上限,必须是Info接口的子类
private T info;
public Person(T info){
this.setInfo(info);
}
public T getInfo(){
return info;
}
public void setInfo(T info){
this.info = info;
}
public String toString(){
return info.toString();
}
}
public class GenericsDemo24{
public static void main(String args[]){
Person<Contact> per1 = new Person<Contact>(new Contact("上海市", "136****xxxx", "021"));
System.out.println(per1);
Person<Introduction> per2 = new Person<Introduction>(new Introduction("forfan06", "male", 27));
System.out.println(per2);
}
}
10.11 本章要点
- 泛型可以使程序的操作更加安全,可以避免发生类转换异常ClassCastException
- 在城中如果使用类时没有指定泛型,则泛型将会被擦除,转而使用Object接收参数
- 可以使用通配符“?”接收全部的泛型类型对象。
- 通过<? extends 类A>可以设置泛型的上限; 通过 <? super 类B>可以设置泛型的下限。
- 泛型方法可以定义在泛型类中,也可以定义在普通类中。
- 泛型可以在接口中定义,实现泛型接口的子类要指明具体的泛型类型
- 泛型可以嵌套使用
- 在程序中定义没有方法的接口,这样的接口一般称为标识接口
10.12 习题
定义一个操作类:要求完成一个数组操作类,其中可以加入任意类型的数据,数组具体的操作类型由程序外部决定,并且可以实现查询功能。