强类型、弱类型、静态类型、动态类型语言

4,832 阅读3分钟

强类型与弱类型语言

强类型语言

1974年,两位美国计算机科学家Liskov,Zilles提出强类型语言的概念。

在强类型语言中,当一个对象从调用函数传递到被调用函数时,其类型必须与被调用函数中声明的类型兼容

function A(){
    B(x)
}
function B(y){
    // y可以被赋值x,程序运行良好
}

这是一个较为宽泛的定义,并没有阐述具体的规则,后人对强类型语言的定义则会更精确一些。

强类型语言:不允许改变变量的数据类型,除非进行强制类型转换。

以java为例

public class HelloWorld {
    public static void main(String []args) {
	int x =1;
	boolean y = true;
	x = y;
        System.out.println(x);
    }
}

定义x为数字,y为布尔值,将y赋值给x,会报错。

public class HelloWorld {
    public static void main(String []args) {
	int x =1;
	char y = 'a'
	x = y;
        System.out.println(x);   // 97
    }
}

定义x为数字,y为字符,将y赋值给x,最终值为97,Java在这里进行了强制类型转换,将字符a的ASCll码赋值给了x,这样x的数据类型依旧是整型。

弱类型语言

弱类型语言:变量可以被赋予不同的值

仍然是刚才的例子,在浏览器中用js来运行。

可以看到,x的类型变成了它被赋值的那个变量的类型。

总而言之,强类型语言对变量的类型的转换有严格的限制,除非进行强制类型转换,不同类型的变量是不能相互赋值的,这样就可以避免一些低级错误。而弱类型语言就没有什么约束,可以很灵活地进行类型转换,但也更容易产生bug。

静态类型语言与动态类型语言

静态类型语言:在编译阶段确定所有变量的类型。
动态类型语言:在执行阶段确定所有变量的类型。

用一个例子来说明:

class C {
    constructor(x, y) {
        this.x = x;
        this.y = y;
    }
}

function add(a) {
    return a.x + a.y;
}

var c1 = new C(10, 20);
var c2 = new C('hello', 'world');

console.log(add(c1));  // 30
console.log(add(c2));  // helloworld

定义一个类C,并为它添加了两个属性x和y,然后定义了一个add函数,用来把一个实例的所有属性相加。当JS编译器看到这段代码时,它完全不知道add函数里的参数a的类型是什么,只有执行的时候才知道。最终c1是数字相加,c2是字符串拼接。

同样的代码,用c++实现

class C {
    public;
        int x;
        int y;
}

int add(C a) {
    return a.x + a.y;
}

在编译的时候,就知道C里面的属性x和y的类型是整型了。

从内存分配的角度来看上面的例子,c++由于一开始就定义好了属性类型是整型,所以假设x是基地址,那么y就在基地址+4的位置上。js则不同,由于一开始不知道属性类型,所以也不知道每个属性要占多少地址空间,所以需要额外的空间存储属性名,在程序运行时,再动态计算属性的地址偏移量。

由此看来,动态类型语言在空间占用上会有一些损耗。

总结一下两者的区别

静态类型语言     动态类型语言    
对类型检查严格 对类型检查宽松
立即发现错误 BUG不易被发现
运行性能较好 运行性能较差
自文档化 可读性较差

但动态类型语言也有方法来补救这些缺点,比如,

  • 性能是可以改善的(V8引擎),语言的灵活性不可或缺
  • 隐藏的错误可以通过单元测试发现
  • 文档通过工具生成

所以虽然js是一门动态弱类型语言,但它却是目前最流行的语言之一,就是因为它的灵活和应用场景广泛。

最后,看一下各种语言的强弱类型和动态静态类型吧。