当前位置: 首页 > 互联网 > 正文

理解编译时与运行时

在面象对象的开发过程中,经常会用到面象对象的多个特性,比如:继承和多态。继承通俗的讲就是可以用子类去扩展父类的方法和属性,可以直接用父类的引用指向子类的对象。而在运行的过程中,程序会根据引用对象的根本类型判断应该调用的方法,有的可能就是重载子类的方法,这就是多态。那么要如何判定程序的编译正确与否,以及运行时是否正确的执行,这里我们需要理解两个概念,编译时和运行时。

编译时:指的是编译器将你的程序代码编译成机器能识别代码的过程。在这个过程中,编译器会根据各个语言的规范,指出哪些代码会编译出错,无法通过。无法通过编译的代码当然无法执行。看下面这个例子。

[code lang=”java”]
class Base{
public void func1(){ System.out.println("B-func1"); }
}

class Sub extends Base {
public void func1() { System.out.println("S-func1"); }
public void func2() { System.out.println("S-func2"); }
}

public class Test{
public static void main(String arg[]){
Base s = new Sub();
s.func2();//编译出错,func2没有在类Base中定义
}
}
[/code]

如上代码所示,标准行出现了编译错误,func2没有在类Base中定义。s是由Sub类创建,但被基类Base引用所指向,所以s只能调用Base的方法和成员属性。无法调用Sub类的成员方法。这时要调用就要加上强制转换再调用:

[code lang=”java”]

((Sub)s).func2();

[/code]

编译时,不仅会检查各种定义,调用的规范,有的编译器还会对代码进行编译优化,比如:那些不变的静态变量的计算过程及赋值,可能直接就被计算结果所替换。还有一些泛型类或是C#中的语法糖都会编译成原始的代码处理方法等等。

运行时:有些基类的方法在子类实现了继承,而在代码中往往用的是基类的调用。这种情形下,只有在运行的时候根据调用对象的根本类型来判定调用的是基类方法还是重载方法。比如下例代码:

[code lang=”java”]

public class Test{
public static void main(String arg[]){
Base s = new Sub();
s.func1();
}
}

[/code]

s调用了func1()函数。因为Base中定义了func1()成员函数,所以编译通过不会报错,但此时s调用的是Base类中的func1()方法,还是Sub类中的func2方法呢?s本质是Sub类对象,这可以通过s.getClass().getName()方法来得到。Sub类重写了Base类的func1()方法,因此这里在运行时,s会调用其根本类的即Sub类的func1()方法,而不是Base类中的func1()方法。这也是面象对象多态的特性之一。

编译时往往检测的是代码编写是否违反语言规范,而运行时指的是对象的动态执行过程。理解编译时与运行时有助于对我们对继承与多态的理解。

本文固定链接: http://www.byhard.com/?p=1539 | 海纳百川

该日志由 byhard 于2016年03月15日发表在 互联网 分类下,
原创文章转载请注明: 理解编译时与运行时 | 海纳百川
关键字: , ,

理解编译时与运行时:目前有2 条留言

  1. 板凳
    土鸡价格:

    编译时往往检测的是代码编写是否违反语言规范,而运行时指的是对象的动态执行过程。

    2016-03-15 16:51
  2. 沙发
    好文推荐:

    过俩看看

    2016-03-15 21:46