Java泛型所给予的编译期检查,是根据该泛型对象的引用类型来定的,如果泛型类对象的引用类型的< >
里有具体类型,那么就会执行相应的编译期检查。
此例将使用ArrayList,代码能通过编译。在new ArrayList的时候可以给定具体类型,用来接对象的引用也可以给定具体类型,将从这两个方面来设计例子:
import java.util.ArrayList;
public class test {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<String>();
list.add("str"); //编译通过
//list.add(1); //编译错误
String str = list.get(0); //返回类型就是String
//表现和上一个完全一样
//相当于ArrayList<String> list1 = new ArrayList<String>()
ArrayList<String> list1 = new ArrayList();
list1.add("str"); //编译通过
//list1.add(1); //编译错误
String str1 = list1.get(0); //返回类型就是String
ArrayList list2 = new ArrayList<String>();
list2.add("str"); //编译通过
list2.add(1); //编译通过
Object object = list2.get(0); //返回类型就是Object
new ArrayList<String>().add("11"); //编译通过
//new ArrayList<String>().add(22); //编译错误
String str2 = new ArrayList<String>().get(0); //返回类型就是String
}
}
ArrayList<String> list = new ArrayList<String>()
,初始化和引用都给定了具体类型以String,注意这里必须是一样的。这是最常用的写法,编译器将执行检查(list1.add("str")
处编译检查通过,list.add(1)
编译检查通不过),并添加隐式的类型转换(String str1 = list1.get(0)
处)。另外有个知识点,这种写法编译器会提示有种更简洁的写法:ArrayList<String> list = new ArrayList<>()
。ArrayList<String> list1 = new ArrayList()
,虽然初始化时没有给定具体类型,但由于引用类型给了具体类型以String,所以当使用这个引用时,会执行同样的编译期检查。ArrayList list2 = new ArrayList<String>()
,虽然初始化时给定了具体类型以String,但由于引用类型却没有给具体类型,由于之后都是对这个引用的对象调用方法,而这种引用属于原生类型,所以没有了编译期检查(add什么类型进去都可以了),而且原生类型里所有的类型参数被替换以Object,所以get函数返回的是Object类型。- 接下来的三行代码,对刚初始化的ArrayList调用方法,此时没有引用,则这里应该直接分析其给定的具体类型。比如
new ArrayList<String>()
只能add字符串,new ArrayList<String>().get(0)
返回的也是字符串。
所以说,泛型类对象的引用类型(是raw type,还是给了类型参数以具体类型)才对编译期检查起作用。
另外,代码有运行时异常,但这无所谓,因为本文关注点在于编译期检查。