コンパイラは他のクラスとそのプロパティをどのように知っていますか?


14

私はオブジェクト指向で、これまでのところ単一の「クラス」を作成するのに適した最初のプログラミング言語を書いています。しかし、の私は、クラスに持って言いたいとしましょうClassAClassB。これら2つが互いに関係ない場合、すべてが良好です。ただし、たとえばClassAClassB次の2つの関連する質問が発生します。

-どのようにコンパイルするコンパイラを知っているだろうClassAということClassBにも存在し、それがない場合、どのようにそれはそれは性質を知っているんでは?

これまでの私の考えは、各クラスを一度にコンパイルする(つまり、スキャン、解析、コード生成)代わりに、各「ファイル(実際にはファイルではなく、「クラス」)ごとに最初にスキャン+解析する必要がありますか? 、すべてのコードを生成しますか?

回答:


13

異なる言語(およびコンパイラー)のアプローチは異なります。

Cファミリでは、さまざまなモジュールに、オブジェクトの構築中に使用される対応するヘッダーファイルがあります。ヘッダーファイルは、オブジェクトのサイズと、呼び出される可能性のある関数またはメソッドに関する情報を提供します。これにより、メモリの割り当てに必要な情報が得られ、「そのメソッド/関数/手順は存在しますか?」ソース自体にアクセスする必要のない単一ユニットのコンパイルを行うときに使用されます。

Javaでは、コンパイラはクラスパス上のことを認識し、それらのオブジェクトを検査してリンクします(メソッドが存在すること、適切な数の引数を持っていることなどを検証します)。Javaは、実行時のロード時に、いつコンパイルされたかについて何も知らない他のクラスで動的にリンクすることもあります。動的ロードの例については、Class.forNameを参照してください。

どちらのオプションも非常に有効であり、独自の利点と欠点があります。ヘッダーファイルを提供することは、面倒でDRYに違反していると考える人もいます。一方、ヘッダーファイルがない場合は、コンパイラとリンカーがライブラリを検査する必要があります-.soまたは.dllには、オブジェクトを適切にインスタンス化するか、メソッド呼び出しを検証するのに十分な情報が含まれていない可能性があります(マシンに依存します)。


0

実際には、Javaを使用すると、IDEはプログラム全体を一度に見ます。ClassBが参照されると、IDEコンパイラはそれを調べます。ライブラリを含むすべてが1つの完全な全体です。プログラムの準備ができたら、クラスパスを変更し、個々の.classファイルをスワップインおよびスワップアウトし、ライブラリバージョンを切り替えることができます。IDEを使用せずに(または何らかの方法でチェックを回避して)個々の.javaファイルをコンパイルすることもできます。結果はまったく一貫している必要はなく、そうでない場合実行時例外が発生します。(IDEがあなたのためにしようとしている多くのことの1つは、実行時エラーをコンパイル時エラー、またはむしろ編集時エラーに変換することです。)

C#はほぼ同じであり、CとC ++が実際にそれほど違うとは思いません。JavaとC#IDEがしていることは、背後でC / C ++スタイルのヘッダーを作成するだけです。


Javaコンパイラは、必要に応じて依存するものもコンパイルします。あなたがきた場合は、この種のものから実行時例外を取得のみ本当にもの(例えば、そのAPIの消費者をコンパイルした後APIを変更して再コンパイル)を強制することは非常に懸命に試みました。
ドナルドフェローズ

@DonalFellows:私の問題は、ライブラリが欠落している(「しかし、それをすべてのマシンに置きます!」)および実行中のプログラムを再コンパイルする(意図せずに.classファイルをホットスワップする)ことです。私はまだそれをやっていませんが、メインプログラムと一致しないパッケージの更新を予見できます。私何年も前にCと.dllを使って多くのことをしました(そして私にそれをしてもらいました)。私は、当時はなかった多くの保護が現在行われていると信じています。
ラルフシャピン

IDEがコンパイラ/リンカーがコンパイル/リンカーの問題を解決する方法をどのように知っているかに関係することを本当に知りません。間違っている場合は修正しますが、IDEは問題全体に完全に直交しています(ただし、プログラマーの作業を容易にすることを除く)。どうして?理論上、IDEはバックグラウンドでコンパイラを使用するためです。
トーマスエディング14年

@ThomasEding:その通りです。この質問に答えたとき、IDEをコンパイラ/リンカーから分離するのに問題があるように見えました。私の言い訳:Javaはそれが実行されるまで「リンク」しないので、それまでクラス参照またはメソッド呼び出しが間違っていることを知ることができません。IDEは実際に私のタスクを「緩和」せず、それを可能にします。コンパイル時、リンク時、実行時にエラーを取得するために(ずっと前にFORTRANとCで)使用していました。入力すると、ほとんどすべてのエラーが正しく表示されるようになりました。これにより、ある意味、IDEはコンパイラ、リンカ、および実行プログラムになります。現在、すべての非ランタイムエラーはIDEから発生しています。
ラルフシャピン14年

0

古い言語はより厳密な場合があります。Javaで可能なことを検討してください。

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

public class Implem implements Ifc {
}

上記のアンチパターンを見てきましたが、それは本当にugいものです(それを禁止していました)。両方のコンパイル単位は互いに使用します。しかし、Ifcは、コンパイルされたImplemなしでコードにコンパイルできます。C .objに相当するコンパイル済みコード.classには、パラメーターなしのコンストラクターを呼び出すImplemのインポートである「リンケージ情報」が含まれていますImplem()。Implemクラスは問題なくコンパイルできます。一部はClassLoader-初期化/ JVMクラスデータの構築、および一部はJava仮想マシン自体が、すべてを統合するリンカーとして機能します。

たとえば、特定のライブラリのあるバージョンでコンパイルし、そのライブラリの別のバージョンで実行すると、ランタイムエラーが認識されます。

したがって、答え:コンパイルは、コンパイルされたオブジェクトコードの単位を提供します。これは、リンクするためのコード+データ+ APIとして見る必要があります。

コンパイラーはその後、一緒にパッキングを行い、リンケージAPI を検証する必要があります。第二段階。

これはいらいらし、見栄えが悪いかもしれませんが、数学的な証明は同じように動作する可能性があります。全体の正確さを証明する際に、検証まで真実である部分をすでに考慮するかもしれません。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.