Java編程思想中的一段話:
當編寫一個java源代碼文件時,此文件通常被稱為編譯單元(有時也被稱為轉譯單元)。每個編譯單元都必須有一個后綴名.java,而在編譯單元內則可以有一個public類,該類的名稱必須與文件的名稱相同(包括大小寫,但不包括文件的后綴名.java)。每個編譯單元只能有一個public類,否則編譯器就不會接受。如果在該編譯單元之中還有額外的類的話,那么在包之外的世界是無法看見這些類的,這是因為它們不是public類,而且它們主要用來為主public類提供支持。
理解:
每編寫一個Java文件就是Java編譯器編譯Java源代碼的一個編譯單元,具體怎么編譯呢?這個就需要去了解Java編譯器的工作原理了。編譯器每編譯一個.java文件(編譯單元),對應着.java文件中的每個類都會有一個輸出文件,而該輸出文件的名稱與.java文件中每個類的名稱相同,只是多了一個后綴名.class。因此,在編譯少量.java文件之后,會得到大量的.class文件。在.java文件中,不是必須含有public類的。public類只是用來表示編譯單元中存在公開接口。
但如果含有public類,最多只能有一個,必須名字和文件名一樣。因為編譯的時候Java編譯器會判斷如果存在public類,該類當作這個編譯單元的對外接口,類加載器需要把該類加載。對於一個public類,它是可以被項目中任何一個類所引用的,只需在使用它前import一下它所對應的class文件即可,將類名與文件名一一對應就可以方便虛擬機在相應的路徑(包名)中找到相應的類的信息。如果不這么做的話,就很難去找,而且開銷也會很大。運行的時候則是調用main()函數運行的。
個人總結:
1、Java編譯器在編譯的時候,如果整個Java文件(編譯單元)都沒有public類(對外的公開接口類),類加載器子就無需從這方面直接去加載該編譯單元產生的所有的字節碼文件(.class文件),那么也就是無需去尋找編譯后字節碼文件存放位置。而類名和文件名一致是為了方便虛擬機在相應的路徑中找到相應的類所對應的字節碼文件。所以在沒有public類的Java文件中,文件名和類名都沒什么聯系。
2、如果編譯單元中包含了public類,那么該類對應的字節碼文件當需要被類加載器加載的,這時候就需要讓類加載器知道該字節碼文件的位置,所以就要確保該類與Java文件名稱一致。同時,如果有兩個public類在同一個文件中,而一個文件只能有一個名稱,故兩個public類的名稱就不能同時和文件名一樣,這就造成至少其中有一個public類在編譯的時候編譯不通過,產生類似的提示
3補充一點:如果一個public類的內部類存在的話,那么會生成otherClass&InnerClass.class文件,其實就是為了識別內部類.
java解釋器的運行過程如下:首先,找出環境變量CLASSPATH(可以通過操作系統來設置,有時也可通過安裝程序-用來在你的機器上安裝java或者基於java的工具-來設置)。CLASSPATH包含一個或多個目錄,用作查找.class文件的根目錄。從根目錄開始,解釋器獲取包的名稱並將每個句點替換成反斜杠,以從CLASSPATH根中產生一個路徑名稱(於是,package foo.bar.baz就變成了foo\bar\baz或foo/bar/baz或其他,這一切取決於操作系統)。得到的路徑會與CLASSPATH中的各個不同的項相連接,解釋器就在這些目錄中查找與你所要創建的類名稱相關的.class文件(解釋器還會去查找某些涉及java解釋器所在位置的標准目錄)。
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
另一篇相關文章:
閑着沒事,在網上看到一個帖子在問為什么一個java源文件中只能有一個public類?
網上有人這么回答:http://topic.csdn.net/t/20060528/22/4784755.html
、每個編譯單元(文件)只能有一個public類。這么做的意思是,每個編
譯單元只能有一個公開的接口,而這個接口就由其public類來表示。
我想這或是從軟件架構設計和安全性設計上得出的結論。或者說是java的設計者們從這方面的考慮。或許這真的是一個規范,但我沒有找到相關資料
不曉得到底有沒有這一說話。如果有請知道的同行給出資料來源?
實驗如下:
Test3.java源文件:
class Test1
{
int i = 1;
}
class Test2
{
int i = 2;
public static void main(String[] args)
{
System.out.println("main method");
}
}
C:/javatest>javac Test3.java
C:/javatest>java Test2
main method
注:編譯不會出錯,注意是運行的Test2 因為沒有Test3.class文件生成。如果運行Test3則報錯
找不到該類
C:/javatest>java Test3
Exception in thread "main" java.lang.NoClassDefFoundError: Test3
Caused by: java.lang.ClassNotFoundException: Test3
at java.net.URLClassLoader$1.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
Could not find the main class: Test3. Program will exit.
這個錯誤原因很簡單:JVM中的類加載器找不到Test3.class
同時這里也說明了包含main()的類如果想運行則不一定要是public的。
《深入jvm第二版》中有這樣一句話:
java虛擬機實例通過調用某個類的main()來運行一個Java程序,而這個main()必須是public
static void 並接收一個字符串數組作為參數,任何擁有這樣一個main()的類都可以作為java程
序的起點。
並沒有說擁有main()方法的類一定要是public類。
Test7.java源文件:
class Test5
{
int i = 1;
}
public class Test6
{
int i = 2;
public static void main(String[] args)
{
System.out.println("main method");
}
}
如果運行Test7.java 報錯:
C:/javatest>javac Test7.java
Test7.java:8: 類 Test6 是公共的,應在名為 Test6.java 的文件中聲明
public class Test6
^1 錯誤
這里說明了文件名必須與public類的類名一致,(如果文件中有public類)
這里可以看出如果有多個public類,那么文件名應該是哪個public類的呢?顯然一個java源文件
只能有一個public類。
所以總結如下:一個Java源文件中最多只能有一個public類,當有一個public類時,源文件名必
須與之一致,否則無法編譯,如果源文件中沒有一個public類,則文件名與類中沒有一致性要求。
至於main()不是必須要放在public類中才能運行程序。
以上是通過實驗得出的結論,個人認為到這里已經可以了,如果一定要追問到底,可能要問問java
平台的設計者了。或許,人家會說:這是java的設計和jvm的內部體系結構設計造成,這是一個規
范,沒有為什么。
我的個人博客:http://www.fuhongliang.com/