RSS

从Groovy角度总结计算机语言分类(编译型、解释型;动态类型、静态类型;强类型、弱类型)

随着计算机科学的越来越发达,各种计算机语言可谓是层出不穷,让人眼花缭乱。每一种计算机语言 都有它各自的特点,其实人类语言也一样,眼花缭乱,纷繁复杂,但是我们总能找到作为一类语言的某些 共性,计算机语言也一样,避其具体的语法不谈,计算机语言从划分的维度不同我们可以划分为:编译型 还是解释型;动态的还是静态的;强类型还是弱类型。

有时候恰恰是这些划分让我们更加觉得搞不清楚,下面我们就简单的搞清楚这几种划分方式。

一、编译型和解释型的区别

首先我们知道,计算机直接执行的代码作为人类是很难读懂的,所有的高级语言计算机也是搞不懂的。 那么我们想要计算机能够执行人类认识的高级语言就必须需要一个翻译,编译器和解释器都是这个翻译, 将高级的计算机语言翻译成计算机的可执行代码。

我们所常说的编译型的高级语言就是通过编译器翻译的,而解释型语言就是通过解释器翻译的,理论上 同样的高级语言代码最终翻译成的同平台的可执行机器代码都是相同的。唯一的区别就是翻译的时机不同。

编译型语言是先将源文件全部编译成可执行文件,之后计算机直接执行可执行文件。解释型语言是在计算机 执行的时候才解释,边解释边执行。如果你站在计算机的角度,前者好比是读一本已经翻译好的外文书,可以 是你自己翻译好的也可以是别人帮你翻译好的;后者好比是你直接看一本外文书,而你的大脑就是解释器。

两种方式各有优劣,很显然,作为编译型语言,编译器不得不把所有的源代码都编译完了计算机才能执行, 有时候这个过程是漫长而复杂的;作为解释型语言,只要有解释器,相当于可以直接运行源代码,修改调试 也很方便,不需要编译的过程就可以直接运行。当然,解释型语言相当于是把翻译的过程推延到了程序执行 的时候,所以相对来讲,解释型语言的执行速度比编译型要慢。

我们最常见的编译型语言C/C++,常见的解释型语言比如javascript、ruby、Python。那么Java是编译型 的还是解释型的语言?我们知道Java首先是将源文件编译成.class的二进制文件,因为.class文件的二进制 代码并不是可执行代码,而是一种介于源代码于可执行代码之间的中间代码,因此这一步通常称为预编译。运行 的时候还需要JVM解释执行.class的二进制文件。所以Java应该是结合了编译型与解释型语言的特点。它既 保留了源代码的高抽象、可移植的特点,又已经完成了对源代码的大部分预编译工作,所以执行起来比“纯解释型” 程序要快许多。

实际上随着计算机科学技术的革新,很多时候这种区分已经渐渐模糊。

二、动态类型与静态类型区别

如果说编译型与解释型的区别在于翻译的时机上,那么动态类型与静态类型的区别在于对类型检查的时机上。 简单的说,动态类型语言对数据类型的检查是在程序运行期间,而静态类型语言是在程序的编译期间。

那么我们是不是可以说,所有的解释型语言都是动态类型,所有的编译型语言都是静态类型呢?其实这个不 好妄下定论,因为前面已经说过,很多语言是解释型还是编译型划分已经很模糊,比如Java,Groovy。 我们首先知道Java是静态的,Groovy是动态的,但是他们都是需要将源文件首先预编译成.class文件, 然后由JVM解释执行,所以无论把它们看出是编译型还是解释型,上面的结论都不能同时满足。

当然,我们去纠结这些概念本身是毫无意义的,索性也不用管它。我们主要需要知道的是动态语言和静态 语言在编程上分别能给我们带来什么利弊。

思考以下Groovy代码编译时和运行时分别会不会报错?

String s = new Date()
println(s)

答案是都不会报错,而且程序顺利输出当前时间。那是不是在Groovy中变量声明成什么类型无所谓啊?
再思考以下Groovy代码编译时和运行时分别会不会报错?

int s = new Date()
println(s)

编译时还是不会报错,只是运行时报错了:Cannot cast object ‘Fri May 15 18:18:58 CST 2015’ with class ‘java.util.Date’ to class ‘int’.
还是很简单直白,“原谅我不能把你的Date转成int”。恍然大悟String s = new Date()运行时 不会报错的原因只是Groovy内部在试图将一个对象转成String对象的时候调用的是该对象的toString()方法, 导致它恰巧不会报错。
以上可以得出结论,动态语言是指在运行时进行数据检查,而不是不做数据检查,后者是弱类型语言。 这一点容易混淆,弱类型和强类型下一节将会讲到。

同样,以下代码在运行时也是会报错的,不过不是声明的时候,而是在方法调用的时候。找不到Date类型参数的 my_println 方法。

def my_println(int s) {
    println(s)
}
def s = new Date()
my_println(s)

通过以上的例子我们可以得出结论,动态语言的类型检查是在运行时进行的,编译时不做类型检查。

二、弱类型和强类型的区别

在讨论计算机语言的时候,我们除了说是编译型解释型或者动态类型静态类型之外,我们还经常会讨论某种 语言是弱类型还是强类型。那么什么是弱类型还是强类型呢?
强类型语言就是变量的类型是明确的,一旦一个变量被声明为某种类型,除了通过强制类型转换之外它就永远 被当成该类型处理,比如Groovy。而弱类型恰恰相反,类型几乎可以被忽略,比如javascript。