0:泛型之前
在Java 使用泛型之前,类的设计主要是靠继承来实现的。
如果一个类中需要定义类型,那么就是用的默认的Object,比如下面的例子中的“abc”,123,12.3都是转为Object 存放到ArrayList中。
public class GenericTest {
public static void main(String[] args) {
ArrayList list = new ArrayList();
list.add("abc");
list.add(123);
list.add(12.3);
for (int i = 0; i < list.size(); i++) {
String name = (String) list.get(i); // 1
System.out.println("name:" + name);
}
}
}
如上的代码在编译前是不会报错的,但是在运行时会提示:
Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
at test.first.GenericTest.main(GenericTest.java:24)
这样就会存在类型转换的问题。
另一方面,这个问题在编写代码的过程中并没有错误提示。而是在运行的时候,才提示有这个问题。
所以才引入了泛型。
1:什么是泛型
简单的说,泛型是指参数类型可以动态变化。
正式的说,泛型即“参数化类型”。
泛型就是为解决上面的问题而生
public static void main(String[] args) {
ArrayList<String> list = new ArrayList();
list.add("abc");
// list.add(123);
// list.add(12.3);
for (int i = 0; i < list.size(); i++) {
String name = (String) list.get(i);
System.out.println("name:" + name);
}
}
上面注释的两行,在ArrayList显示声明为String 后会报错。这样,在编译前代码就能保证不会有类型转换出错
2:为什么要用泛型
代码在写的时候就会进行提示,而不是等到编译时才提示异常。
使用泛型使得代码更具有可读性,安全性。
3:泛型的类型通配符
泛型的通配符分为:限定通配符和非限定通配符
限定通配符
分为限上界通配符<? extends T>,下界通配符<? super T>
非限定通配符
<?>
4:泛型的原理
类型擦除
public static void main(String[] args) {
ArrayList<String> arrayString=new ArrayList<String>();
ArrayList<Integer> arrayInteger=new ArrayList<Integer>();
System.out.println(arrayString.getClass());
System.out.println(arrayInteger.getClass());
System.out.println(arrayString.getClass() == arrayInteger.getClass());
}
上面的代码运行结果是:
class java.util.ArrayList
class java.util.ArrayList
true
我们会看到,arrayString和arrayInteger 这两者在编译后都是ArrayList ,没有了它们指定的String 和 Integer类型。
这是因为,在编译期间,所有的泛型类型都会被擦除,而这么做的原因主要是为了防止类型膨胀。
Java的泛型基本都是在编译器这一层实现的,因此也称之为“伪泛型”。
参考: