对泛型的理解一直停留在会简单使用的层面上,对其中的一些概念比如:逆变,协变,PECS的理解始终不是很透彻,尤其泛型跟一些容器类结合时更容易出现一些问题.所以花了几天时间深入学习了一下.今天把学习心得分享一下,希望对大家有所帮助. 我会先介绍一下泛型的基本用法,然后通过一些实际问题引入高阶用法
可以将接口,类和方法声明为泛型.这篇文章主要讲解泛型接口
泛型接口声明
声明接口时,将泛型参数放置到接口名后面的尖括号中,参数的名字要符合java标识符的命名规则,且不能使用保留字.
public interface InterfaceExample1<T> {
T getT(T input);
String getString(T input);
Number getNumber(String input);
}
上例为接口InterfaceExample1声明了一个泛型参数T,然后在方法签名中就可以使用该参数,例如
T getT(T input);
String getString(T input);
T既可以作为方法的参数类型,也可以作为返回值类型,当然你也可以不使用T,例如第三个方法签名Number getNumber(String input)
如果需要,也可以为接口声明多个泛型参数,参数之间用逗号隔开.例如:
public interface InterfaceExample2<T1,T2> {
T1 getT1();
T2 getT2();
}
泛型接口实现
在实现接口时,你可以根据需要选择是否同时指定泛型参数的具体类型
不指定具体类型
/**
* 实现类在实现泛型接口时,可以不指定具体的泛型参数
* 此时参数类型默认为Object
*/
public class Interface1Imp1 implements InterfaceExample1 {
@Override
public Object getT(Object input) {
return input;
}
@Override
public String getString(Object input) {
return input.toString();
}
@Override
public Number getNumber(String input) {
return Integer.valueOf(input);
}
public static void main(String[] args) {
Interface1Imp1 interface1Imp1 = new Interface1Imp1();
System.out.println(interface1Imp1.getT("hello"));
System.out.println(interface1Imp1.getNumber("123"));
System.out.println(interface1Imp1.getString("hello"));
}
}
指定具体类型
当然,你可以像下例一样,指定类型
/**
* 实现类不能改变接口方法的参数类型,但是返回值可以是接口中方法返回值的子类
* 比如getT方法,我们不能将input类型从Number改成Object
* 但是它的返回值可以声明为Number的子类比如Integer
*/
public class Interface1Imp2 implements InterfaceExample1<Number> {
@Override
public Number getT(Number input) {
return input;
}
@Override
public String getString(Number input) {
return input.toString();
}
@Override
public Double getNumber(String input) {
return Double.valueOf(input);
}
public static void main(String[] args) {
InterfaceExample1<Number> interfaceExample1 = new Interface1Imp2();
System.out.println(interfaceExample1.getT(new Integer(123)));
System.out.println(interfaceExample1.getString(new Integer(123)));
System.out.println(interfaceExample1.getNumber("123.23"));
}
}
调用接口方法时指定
或者你可以推迟到调用接口的方式时指定具体类型,比如
public class Interface1Imp4 implements InterfaceExample1 {
@Override
public Object getT(Object input) {
return input;
}
@Override
public String getString(Object input) {
return input.toString();
}
@Override
public Number getNumber(String input) {
return Integer.valueOf(input);
}
public static void main(String[] args) {
//调用方式时才指定参数类型
InterfaceExample1<Integer> interfaceExample1 = new Interface1Imp4();
System.out.println(interfaceExample1.getT(new Integer(123)));
System.out.println(interfaceExample1.getString(new Integer(123)));
System.out.println(interfaceExample1.getNumber("123"));
}
}
总结
通过以上分析我们可以得出如下结论:
- 声明接口时可同时声明一个或多个泛型参数
- 实现类的关键是实现接口的方法签名,具体是否需要同时指定具体的参数可视情况而定
- 如果实现类不指定具体的泛型参数,则参数类型为
Object