编译器如何了解其他类及其属性?


14

我正在写我的第一种面向对象的编程语言,到目前为止,它与创建单个“类”一样好。但是,假设我要上课,说ClassAClassB。只要这两个彼此无关,那么一切都很好。但是,说ClassA创建ClassB-提出了2个相关问题:

-如何将编译时,编译器知道ClassAClassB即使存在,并且,如果是这样,它是如何知道它的属性?

到目前为止,我的想法是:而不是一次编译每个类(即扫描,解析和生成代码),每个“文件”(本质上不是真正的文件,而是一个“类”)我需要先扫描+解析每个类,然后为所有人生成代码?

Answers:


13

不同的语言(以及编译器)对此的处理方式也有所不同。

在C系列中,不同的模块具有在构建对象时使用的对应头文件。头文件提供有关对象大小以及可以调用的功能或方法的信息。这为内存分配提供了必要的信息,并且“该方法/功能/程序是否存在?” 在编译不需要访问源本身的单个单元时使用。

在Java中,编译器知道其类路径上的内容,并检查这些对象以链接到它们(验证方法是否存在,参数数量正确等)。Java也可能在运行时加载时动态链接到其他类,这些类对编译时一无所知。有关动态加载的示例,请参见Class.forName

两种选择都非常有效,并且各有优缺点。提供头文件有些麻烦且违反DRY。另一方面,如果您没有头文件,则编译器和链接器都需要检查库文件-.so或.dll中可能没有足够的信息来正确实例化对象或验证方法调用(并取决于机器)。


0

实际上,使用Java,IDE可以一次查看整个程序。引用ClassB时,IDE编译器将对其进行查看。包括库在内的所有内容都是一个完整的整体。程序准备就绪后,您可以更改类路径,换入和换出单个.class文件,以及切换库版本。您还可以在不使用IDE的情况下编译单个.java文件(或以某种方式避免对其进行检查)。结果根本不需要保持一致,如果不一致,您获得运行时异常。(IDE试图为您做的许多事情之一就是将运行时错误转换为编译时错误,或更确切地说是编辑时错误。)

C#基本相同,我认为C和C ++并没有真正的不同,因为Java和C#IDE所做的只是在幕后为您创建C / C ++样式的标头。


必要时,Java编译器还会编译依赖项。仅当您确实非常努力地强制执行操作(例如,在编译该API的使用者之后更改并重新编译该API)时,您才能从此类事件中获得运行时异常。
Donal Fellows 2012年

@DonalFellows:我的问题一直是缺少库(“但是我把它放在所有机器上!”)并重新编译正在运行的程序(无意间热交换.class文件)。我可以预见,更新软件包将不再与主程序匹配,尽管我还没有完成。几年前,我确实使用C和.dll(并已对我完成了)完成了很多工作。我相信并希望现在有很多保护措施不存在。
RalphChapin 2012年

我真的不了解IDE与编译器/链接器如何知道如何解决编译器/链接器问题有关。如果我错了,请纠正我,但是IDE与整个问题完全正交(除了它减轻了程序员的工作量)。为什么?因为理论上IDE是在后台使用编译器。
Thomas Eding 2014年

@ThomasEding:你说的很对。当我回答这个问题时,我似乎很难将IDE与编译器/链接器分开。我的借口:Java直到运行时才“链接”,因此直到那时才知道类ref或方法调用是错误的。IDE并不能真正“简化”我的任务,而是可以实现的。在编译,链接,然后运行时,我曾用过很长时间(在FORTRAN和C中)。现在,在键入错误时,我几乎可以正确地获得所有这些错误,从某种意义上说,这使IDE成为了编译器,链接器执行器。今天,所有非运行时错误都来自IDE。
RalphChapin 2014年

0

较旧的语言有时更严格;考虑一下Java中可能发生的情况:

public interface Ifc {
    public static final Ifc MY_CONSTANT = new Implem();
}

public class Implem implements Ifc {
}

我已经看到了上面的反模式,而且确实很丑陋(我本来会禁止的)。两个编译单元互相使用。但是Ifc可以编译为代码而无需编译的Implem。类似于C .obj的已编译代码.class包含“链接信息:” Implem的导入,调用无参数构造函数Implem()。然后可以毫无问题地编译Implem类。部分是ClassLoader-执行初始化/构建JVM类数据,部分是Java虚拟机本身,充当链接器,集成所有内容。

例如,使用特定库的一个版本进行编译,然后使用该库的另一个版本运行,将识别运行时错误。

答案就是:编译提供了已编译目标代码的单元,必须将它们视为代码+数据+用于链接在一起的API。

此后,编译器还应一起打包,并验证链接API;第二阶段。

这可能会令人烦恼并且看起来不雅,但是数学证明可能以相同的方式起作用:在证明整个正确性之前,人们可能已经考虑过一个部分,直到验证。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.