题主是一名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文件,没有包名的目录结构。
再次感谢大家的解答。
1,Java的bytecode裡面有方法的原型資訊,編譯時有class檔案即可
2,Java運行時從classpath裡面尋找jar檔,再在jar檔裡面找包名對應的a/b/c.class
3,是這樣的
看一本關於講解jvm的書,具體的細節,看看類加載,《深入jvm虛擬機》。
1、:全類名定義一個類,每個類被載入一次。
2、:你是想問怎麼找到吧,我覺得跟全類名比較類似。
最後個我沒懂你的意思
我個人是這樣理解的:
1、c/c++編譯出的函式庫和java產生jar包這兩件事情是不等價的,jar包本質上只是一個壓縮包;如果一定要類比,c/c++編譯的過程應該相當於java產生class檔案的過程,也就是程式碼轉換成機器(或虛擬機器)可以理解並執行的檔案;
2、JAVA虛擬機會把目標class檔案載入到記憶體裡,其中類別的信息應該放到“方法區”,被實例化的時候,引用在堆疊、實例在堆(和c/c++的malloc或new類似)。
3、每一個類別是透過類別載入器+ 套件名稱+ 類別名稱三部分資訊在JVM中唯一識別;
4、比較好的書有《深入理解java虛擬機》、《osgi原理與最佳實務》 ;
1,如果A.java依賴了xxx.jar包,在編譯時(例如javac指令),需要在classpath把xxx.jar包含進去,編譯器在編譯A.java的時候,會去找xxx.jar包,看看是否有A所依賴的類,所依賴的類別是否有對應的方法,等等。不知道這樣是否是你所說的保證使用了正確的原型。
2,Java要求包名必須有對應的檔案系統結構,例如
com.x.y
这个包,就必须有相应的com/x/y/
目录与它对应。这个路径信息在两方面有体现,一个是编译的时候,一个是运行的时候。编译和运行都要指定classpath,可以把这个classpath类比成操作系统的环境变量path,比如我们把
javac
这个命令加到了path环境变量下,需要在把javac
所在的目录加到path上。classpath也一样,无论在运行还是编译的时候,如果你要引用一个类,比如说是
com.a.b.String
,那么首先你得有对应的目录结构com/a/b/
。你可以把com文件夹随便放在硬盘中的某个目录下,比如说放在D:/test
下,那么你需要在classpath里加上D:/test
,這樣,當要引用到com.a.b.String時,編譯器或Runtime會去classpath指定的目錄裡面去找,怎麼找呢,根據包名,然後找對應的目錄結構。目錄結構就在這裡體現出它的作用。
3, 不用在意jar包的命名,因為jar包實際上是一個zip格式的文件,jar包也會被加到classpath下,Java虛擬機真正care的是jar包裡面的目錄結構,以此來確定包名和類別的位置等。只要Jar包有對應的類別就行,你可以對jar包任意改名。
4, Java跟C/C++不一樣的就是Java是跑在Java虛擬機上的,所以了解一下底層的機制的話,十有八九都會往虛擬機器那方面去看。 C/C++的鏈接,裝載,對應到Java裡就是類別載入器(ClassLoader)的原理。這方面的資料可以看《深入理解Java虛擬機》(週志明),或者Oracle官方的Java虛擬機規範(jvms.pdf),到官網找找就有。
其實我覺得樓主的問題更多的是Java這門語言本身的規範,這個可以參考一些教程書,或者oracle官方的Java語言規範(jls.pdf),一樣在Oracle官網找。
請參考《Java Virtual Machine Specification》第五章:Chapter 5. Loading, Linking, and Initializing