-------android培训、java培训、期待与您交流! ----------
1. Java泛型
Java中泛型的概念是JDK1.5引入的。在没有泛型之前,集合类型把所有的集合元素当作Object类型存放,这样当取出元素后,同样也是Object类型的对象,需要进行强制转换才能使用,这样使得代码更为臃肿,而且可能出现ClassCastException异常。
使用了泛型后,集合类型可以记住放入集合的元素类型,取出后无需转换即可使用。同时,泛型对可放入集合的元素类型也进行了限制,非泛型限定的类型的元素无法放入集合,这样保证了程序的健壮性和稳定性。
在不使用泛型的情况下将取出的元素进行强制转换可能导致异常,如下所示:
public class ListTest1 {
public static void main(string[] args) {
//创建一个保存字符串的List集合
List list = new ArrayList();
list.add("黑");
list.add("马");
list.add("程");
list.add("序");
list.add("员");
list.add(1); //由于没有泛型限制,所有的元素作为Object对象添加到list,所以不会报错
for (int i = 0; i != list.size(); i++) {
//取出的元素需要进行强制转换
//但最后一个元素为Int变量,无法转换为String,所以程序会报错,抛出ClassCastException异常
String a = (String)list.get(i);
}
}
使用泛型之后可避免以上问题的出现:
public class ListTest2
{
public static void main(string[] args)
{
//创建一个带泛型的保存字符串的List集合
List<String> list = new ArrayList<String>();
list.add("黑");
list.add("马");
list.add("程");
list.add("序");
list.add("员");
//由于泛型限制了元素类型为String,所以下面的语句无法通过编译
//list.add(1);
for (int i = 0; i != list.size(); i++) {
//取出元素后无需进行强制转换
String a = list.get(i); } }
注意:Java 7 中在使用泛型定义类或接口变量是,那么调用构造器创建对象时不需要显示指定泛型的类型,只需要给出一对尖括号即可。
List<String> list = new List<String>();
List<String> list = new List<>(); //Java 7特性,构造器中可省略泛型的类型信息
2. 泛型类和接口
Java中可以为任何的类或接口添加泛型声明。以下是一个泛型类:
//定义Person中使用了泛型声明,使用T作为泛型的类型参数
public class Person<T>
{
//使用T类型定义变量
private T info;
public Person() {}
//使用了T类型的形参
public Person(T info)
{
this.info = info;
}
public static void main(String args[])
{
//使用String构造Person对象
Person<String> strPer = new Person<>("中国人");
//使用Double构造对象
Person<Double> dPer = new Person<>(3.2);
}
}
注意:当一个类使用泛型声明后,其构造器还是原来的类名,不用添加泛型声明。
3. 类型通配符
当使用一个泛型类时,需要为泛型传入一个类型实参数。但是需要注意的是List<String>不是List<Object>类的子类。需要使用类型通配符。类型通配符是一个问号。讲一个问号作为类型实参传递给List集合,写作List<?>。他的元素可以匹配任何类型。
当直接使用List<?>这种形式时,即表明这个List集合可以是任何泛型的父类。但还有一种特殊的情况,当我们不想使这个List<?>是任何泛型List的父类,只想表示他是某一类泛型List的父类时。可以为其指定上限:
public class Apple<T extends Number> {
T col;
public static void main(String[] args) {
Apple<Integer> ai = new Apple<>();
Apple<Double> ad = new Apple<>();
// 下面代码将引起编译异常,下面代码试图把String类型传给T形参
// 但String不是Number的子类型,所以引发编译错误
Apple<String> as = new Apple<>(); //①
}
}
上面程序定义了一个Apple类,该Apple类的类型形参的上限是Number类,表示使用Apple类时传入的类型实参只能是Number或Number的子类。