最近在学习Java,现在正好学到了Java泛型的内容,这才理解了,为什么Java被称为强类型语言。我之前是通过C语言入门的,C语言是一门弱类型语言,对于可能存在的类型错误,C语言编译器是从来不会报错的,它只会在运行的时候死给你看。而Java对于类型的冲突,在编译阶段就会有严格的检查。例如:
int i = 3.4;
对于这行代码,在C语言中它会完全正常的通过编译,但是在Java中就会提示不兼容类型。
上面只是一个很简单的例子,但由于Java是一门面向对象语言,在加入了类以及类的继承这些概念之后,类型是否兼容的问题就更复杂了,比如这样:
Object obj = new String("hello word");
这里把String类型的值赋给Object类型的变量,这在Java中是允许的,编译时不会有异常,也不会有警告。因为String类是Object类的子类,把子类赋给父类是没有问题的。但反过来,把父类赋给子类就是绝对不允许的。
Java中还存在泛型,当引入泛型之后,类型是否兼容的问题又进一步复杂了。例如:
ArrayList <String> list1 = new ArrayList<String>();
ArrayList <Object> list2 = new ArrayList<String>();
对于上面的两行代码,第一行是完全没有问题的,类型完全兼容。但是如果编译第二行代码,就会出现“不兼容类型”的错误。这是因为,对于泛型的类型检查,比对普通变量的类型检查更为严格。普通变量只要是同样的类型或者存在继承关系都可以赋值成功,但是对于使用了泛型的变量,必须要类型参数完全相同才能赋值,就算存在继承关系也不行。
如果要修改第二行代码,可以修改成下面这样子:
ArrayList <?> list2 = new ArrayList<String>();
这里使用了类型通配符,list2变量会自动采用被赋给它的值使用的类型参数,即在运行时,尖括号里的?会被替换成String,list2变成了一个ArrayListlist2变成了ArrayList<String>类型,那么我们可不可以向其中添加String类型的值呢?
ArrayList <?> list2 = new ArrayList<String>();
list2.add(new String("hello word!"));
编译上面的代码,会发现编译无法通过,提示参数不匹配。但是上面不是把String类型的值添加到容纳String的集合中吗,到底是那里不匹配了?这又牵扯到Java的多态问题了。先看下面两段代码;
ArrayList <?> list1 = new ArrayList<String>();
ArrayList <?> list2 = list1;
ArrayList <?> list3 = list2;
ArrayList <?> list = list3;
//list4.add(new String("hello word!"));
ArrayList <?> list = new ArrayList<String>();
//list4.add(new String("hello word!"));
编译上面两段代码都很正常,没有异常也没有警告,如果仔细考虑上面两段代码,会发现它们的效果是相同的,都是把声明list并把它初始化。不同在于,第一段是用一个变量为list赋值,而这个变量又是由另一个变量赋值的,这样子往上套了几层,最后的list1才由一个构造器来赋值,我们到了这里才确定了list的类型。
如果我们把第一段代码最后一行被注释的代码加进来,那么它就和上面一个例子一样了,编译它,同样也会出现和前面一样的错误。和前面一样,这段代码粗看起来还是没有问题了,类型都是匹配的。但是区别是,我在推断它的类型是否匹配的时候,花费了更多精力。如果我们照着这个模式再写一段代码,让它中间这个赋值过程变得更长,比如我们通过10个中间才完成它的赋值,那我们就得一一检查这十个变量才能确定类型是否匹配。那如果增加到100个,甚至1000个呢?只要愿意,这一系列变量组成的链条可以增加到无限长,如果真的按照前面的套路做类型检查,那么这个成本可就大到无法接受了。
我们再退回来想一想,编译时的错误检查,它的目的到底是什么?它想要做的,应该是用比较小的成本,发现程序在实际运行时可能出现的问题,最终它总会面对一个成本和精确性的矛盾。对于上面的问题,对于成本的考虑让它无法真的把程序全面的运行一遍来检查可能错误。
最后,Java采取的策略是,对一个变量的所有操作的检查都基于这个变量被声明的类型,即编译态。任何与编译态相冲突的操作都会被禁止,比如在上面的例子中,list被声明的类型是ArrayList <?>,从这里编译器并不能推断出它包含的值的类型,往其中添加任何类型的值都存在不匹配的可能。所以向其中添加任何元素都会报错。这就是Java的强类型检查的体现。
浙公网安备 33010602011771号