题主是一名C/C++程序员,刚开始学习java。
疑惑如下:
java没有头文件,当调用第三方包(无源码)的方法,编译器如何保证程序员使用了正确的原型呢?
定义包时,为了保证包名唯一,使用package a.b.c语法,包的类需要在文件系统的a/b/c目录下。但当其他java程序使用该包时,这个路径信息怎么在运行查找这个包时体现?
某c程序编译时依赖库liba.so,那么运行时系统必须提供库liba.so,但是java程序编译时使用abc.jar,但是运行时可以提供bcd.jar,只要bcd.jar里具有该java程序用到的类就行?(我自己瞎猜的,请问这个说法对不对?)
最后,java有没有类似于《链接、装载与库》这样的书籍,或者请大家推荐一些可以了解原理的书籍,能够解答这些困惑,中英文皆可。
感谢。
非常感谢大家的解答,试着将各位的回答总结整理如下:
jar包里的class文件中含有文件原型。c/c++的libxxx.so/libxx.a中只有符号,没有原型,原型由头文件中提供;java的class文件中即含有原型信息。编译器只要解析class文件即可知道程序员是否使用了正确的原型。(@fredric_201 与 @心不在焉 )
jar包即zip包,里面存在目录结构,该结构与包名结构完全一致(标准jar包,非android jar包)。(@心不在焉 与 @beanlam)
说法正确。java程序依赖的实际是class,jar包只是一组class的zip包,其命名无关紧要,因此可以任意修改。如果非要和c/C++进行对比,libxx.so类似于.class,而非jar包。(@心不在焉 与 @beanlam)
笔者在ubuntu机器上使用zipinfo查看openjdk自带的jar包,如下:
prife@droi: /usr/lib/jvm/java-7-openjdk-amd64/jre/lib
$ zipinfo rt.jar
...
-rw---- 2.0 fat 24298 bl defN 15-Jul-24 08:17 java/lang/String.class
-rw---- 2.0 fat 1734 bl defN 15-Jul-24 08:17 java/lang/Object.class
可以看到rt.jar包里具有跟包名完全一致的目录结构。
最后感谢大家推荐的书籍:
《深入理解java虚拟机》
《Java Virtual Machine Specification》
PS. 笔者之所以对第二点看到困惑,因为作为Android程序员,发现安卓的jar包里是只有dex文件,没有包名的目录结构。
再次感谢大家的解答。
ringa_lee2017-04-18 09:23:50
1. Java のバイトコードにはメソッドのプロトタイプ情報が含まれており、コンパイル時にはクラス ファイルで十分です。
2. Java は、クラスパス内で jar ファイルを探します。 /bはjarファイル内のパッケージ名に対応します。/c.class
3は次のようになります
伊谢尔伦2017-04-18 09:23:50
JVM に関する書籍を読んでください。具体的な詳細については、「詳細な JVM 仮想マシン」のクラスローディングを参照してください。
1.: 完全なクラス名でクラスを定義し、各クラスは 1 回ロードされます。
2. 完全なクラス名と似ていると思います。
最後の意味がわかりません
黄舟2017-04-18 09:23:50
私の個人的な理解は次のとおりです:
1. C/C++ によってコンパイルされたライブラリと Java によって生成された jar パッケージは、本質的には単なる圧縮パッケージです。 C/C++ コンパイル プロセスは、Java がクラス ファイルを生成するプロセスと同等である必要があります。つまり、コードは、マシン (または仮想マシン) が理解して実行できるファイルに変換されます。
2. JAVA 仮想マシンは、ターゲットクラスファイルをメモリにコピーすると、クラス情報は「メソッド領域」に配置されます。インスタンス化されると、参照はスタック上にあり、インスタンスはヒープ上にあります (C/C++ の malloc または new と同様)。
3. 各クラスは、クラス ローダー + パッケージ名 + クラス名という 3 つの部分の情報によって JVM 内で一意に識別されます。
4. より良い書籍には、「Java 仮想マシンの詳細」、「OSGI」などがあります。原則とベストプラクティス」;
怪我咯2017-04-18 09:23:50
1. A.java が xxx.jar パッケージに依存している場合は、コンパイル時に xxx.jar をクラスパスに含める必要があります (javac コマンドなど)。コンパイラーは A.java をコンパイルするときに xxx を検索します。 jar パッケージを使用して、A が依存するクラスがあるかどうか、依存するクラスに対応するメソッドがあるかどうかなどを確認します。これが、正しいプロトタイプが使用されるようにするために と言ったことなのかどうかはわかりません 。
2. Java では、パッケージ名に対応するファイル システム構造が必要です。たとえば、パッケージ com.x.y
には、それに対応する com/x/y/
ディレクトリが必要です。このパス情報は、コンパイル時と実行時の 2 つの側面に反映されます。
コンパイルと実行の両方でクラスパスを指定する必要があります。このクラスパスは、オペレーティング システムの環境変数パスと比較できます。たとえば、コマンド javac
をパス環境変数に追加する場合、次のディレクトリを追加する必要があります。 javac
はパス上にあります。
クラスパスについても同様です。実行時でもコンパイル中でも、com.a.b.String
などのクラスを参照したい場合は、まず対応するディレクトリ構造 com/a/b/
を用意する必要があります。 com フォルダーをハード ディスク上の任意のディレクトリ (たとえば D:/test
の下) に置くことができます。その場合は、クラスパスに D:/test
を追加する必要があります。これにより、com.a.b.String を参照したい場合は、サーバーまたはランタイムはクラスパスで指定されたディレクトリに移動します。パッケージ名に従って、対応するディレクトリ構造を見つけます。
ディレクトリ構造は、ここでの役割を反映しています。
3. jar パッケージの名前は気にする必要はありません。jar パッケージは実際には zip 形式のファイルであり、Java 仮想マシンが実際に気にするのはクラスパスにも追加されるためです。 jar パッケージ内の ディレクトリ構造。パッケージ名やクラスの場所などを決定します。 Jar パッケージに対応するクラスがある限り、jar パッケージの名前を任意に変更できます。
4. Java と C/C++ の違いは、Java は Java 仮想マシン上で実行されるため、基礎となるメカニズムを理解していれば、仮想マシンに注目することになるでしょう。 C/C++ のリンクとロードは、Java のクラスローダー (ClassLoader) の原理に対応します。この分野の情報については、『Java 仮想マシンの詳細な理解』 (Zhou Zhiming)、または Oracle の公式 Java 仮想マシン仕様 (jvms.pdf) を参照してください。 Webサイト。 実際には、投稿者の問題は Java 言語自体の仕様にあると思います。これについては、いくつかのチュートリアル本、または Oracle の公式
Java 言語仕様(jls.pdf) を参照してください。これは、Oracle の公式 Web サイトの「Find it」からも入手できます。