什么是动态类型语言?
类型检查的主体过程是在运行期的语言就是动态类型语言。如JavaScript。
相对的,类型检查的主体过程在编译期的语言是静态类型语言。如Java。
从定义中可以看出决定一个语言是不是动态语言有关键两点:
1、类型检查;
2、进行类型检查的时期,在运行期的是动态类型语言,反之在编译期检查的是静态类型语言。
为了更形象的理解这个概念,我们不妨来看下面这段代码:
abstract class Animal{
public abstract void run();
}
class Dog extends Animal{
@Override
public void run() {
System.out.println("Dog run.");
}
}
class Man{
public void run(){
System.out.println("Man run.");
}
}
public void executeRun(Animal animal){
animal.run();
}
相信基本所有读者都能看出这段代码只会执行Animal子类的run()方法,绝不会执行到Man类的run()方法。
造成这个现象的原因就是编译期的类型检查,Java在编译期间就把run()方法的完整符号引用生成了出来,作为方法的调用指令存储到class文件中,生成的符号引用就包含了方法定义在哪个具体类型中,因此,在运行时,就只能执行该种类型的run()方法(动态类型语言可以在运行时执行任意一个类型的run()方法)。
Java在1.7中,在之前的单纯依靠符号引用来确定调用的目标方法之外,提供了一种新的动态确定目标方法的机制,称为MethodHandle。来看下面这一段代码:
static class PrintlnA {
public void println(String s) {
System.out.println("A print:" + s);
}
}
static class PrintlnB {
public void println(String s) {
System.out.println("B print:" + s);
}
}
public static MethodHandle findMethodHandle(Class clazz) throws
NoSuchMethodException, IllegalAccessException, InstantiationException {
MethodType methodType = MethodType.methodType(void.class, String.class);
return MethodHandles.lookup().findVirtual(clazz, "println",
methodType).bindTo(clazz.newInstance());
}
public static void main(String[] args) throws Throwable {
Class clazz = System.currentTimeMillis() % 2 == 0 ? PrintlnA.class :
PrintlnB.class;
findMethodHandle(clazz).invokeExact("afdsafdsafafads");
}
通过MethodHandle就可以让Java拥有动态类型语言的特性,在运行时才确定方法所在的具体类型。