簡體   English   中英

為什么每個公共類都在一個單獨的文件中?

[英]Why is each public class in a separate file?

我最近開始學習Java,發現很奇怪每個Java類必須在一個單獨的文件中聲明。 我是C#程序員,C#沒有強制執行任何此類限制。

為什么Java會這樣做? 有任何設計考慮因素嗎?

編輯(基於幾個答案):

為什么Java現在還沒有在IDE時代消除這種限制? 這不會破壞任何現有代碼(或者它會嗎?)。

我剛剛采用了一個C#解決方案並且做了這個(刪除任何包含多個公共類的文件)並將它們分解為單個文件,這使生活變得更加容易。

如果文件中有多個公共類,則會遇到一些問題:

  1. 你怎么命名這個文件? 公共課程之一? 另一個名字? 人們在糟糕的解決方案代碼組織和文件命名約定方面存在足夠的問題以產生一個額外的問題

  2. 此外,當您瀏覽文件/項目資源管理器時,事情並未隱藏。 例如,您可以看到一個文件並向下鑽取,並且共有200個類。 如果您有一個類的一個文件,則可以更好地組織測試並了解解決方案的結構和復雜性。

我認為Java是正確的。

根據Java語言規范,第三版

這種限制意味着每個編譯單元最多只能有一個這樣的類型。 這種限制使得Java編程語言的編譯器或Java虛擬機的實現很容易在包中找到命名類 ; 例如,公共類型wet.sprocket.Toad的源代碼可以在wet / sprocket目錄中的Toad.java文件中找到,相應的目標代碼可以在同一目錄中的Toad.class文件中找到。

重點是我的。

看起來基本上他們想要將操作系統的目錄分隔符轉換為命名空間的點,反之亦然。

所以是的,這是某種設計考慮因素。

來自Java的思考

每個編譯單元(文件)只能有一個公共類。
這個想法是每個編譯單元都有一個由該公共類表示的公共接口 它可以擁有任意數量的支持“友好”課程。 如果編譯單元中有多個公共類,編譯器將給出錯誤消息。


規范(7.2.6)

當包存儲在文件系統(?7.2.1)中時,如果在由類型名稱加上名稱的文件中找不到類型,主機系統可以選擇強制執行編譯時錯誤的限制。如果滿足以下任一條件,則為擴展名(例如.java或.jav)

  • 該類型由聲明類型的包的其他編譯單元中的代碼引用。
  • 該類型被聲明為public(因此可以從其他包中的代碼訪問)。
  • 這種限制意味着每個編譯單元最多只能有一個這樣的類型。
  • 這種限制使得Java編程語言的編譯器或Java虛擬機的實現很容易在包中找到命名類 ; 例如,公共類型wet.sprocket.Toad的源代碼可以在wet / sprocket目錄中的Toad.java文件中找到,相應的目標代碼可以在同一目錄中的Toad.class文件中找到。

簡而言之:它可能是關於查找類而無需在類路徑上加載所有內容。

編輯:“可以選擇”似乎它留下了遵循該限制的可能性,並且“可能”的含義很可能是RFC 2119中描述的那個(即“可選”)
但實際上,這是在很多平台上實施的,並且依賴於如此多的工具和IDE,我沒有看到任何“主機系統”選擇強制執行該限制。


從“ 曾經的橡樹......

這很明顯 - 就像大多數事情一旦你知道設計原因 - 編譯器必須通過所有編譯單元(.java文件)進行額外的傳遞,以找出哪些類在哪里,這將使編譯更慢。

(注意:

Oak版本Oak語言規范0.2 (后記文檔): Oak是現在通常稱為Java的原始名稱,本手冊是Oak(即Java)最早的手冊。
有關Java起源的更多歷史,請查看綠色項目Java(TM)技術:早期歷史

這只是為了避免混淆 ,因為從開發人員的角度來看,Java是以簡單的方式創建的。 您的“主要”類是您的公共類,如果它們位於具有相同名稱的文件中並且位於類的包指定的目錄中,則它們很容易找到(由人工)。

您必須記住,Java語言是在90年代中期開發的, 在IDE進行代碼導航和搜索之前的日子里

如果一個類僅由另一個類使用,則將其設為私有內部類。 這樣,您就可以在文件中擁有多個類。

如果一個類被多個其他類使用,那么這些類中的哪一個會放入同一個文件中? 所有這三個? 您最終會將所有課程都放在一個文件中......

這就是語言設計者決定如何做到這一點。 我認為主要原因是優化編譯器傳遞 - 編譯器不必猜測或解析文件來定位公共類。 我認為這實際上是一件好事,它使代碼文件更容易找到,並迫使你遠離過多的文件。 我也喜歡Java如何強制您將代碼文件放在與包相同的目錄結構中 - 這樣可以輕松找到任何代碼文件。

在一個文件中包含多個Java頂級類在技術上是合法的。 但是,這被認為是不好的做法,如果您這樣做,許多Java工具(包括IDE)都不起作用。

JLS說:

當包存儲在文件系統(第7.2.1節)中時,如果在由類型名稱加上名稱的文件中找不到類型, 主機系統可以選擇強制執行編譯時錯誤的限制。如果滿足以下任一條件,則為擴展名(例如.java或.jav):

  • 該類型由聲明類型的包的其他編譯單元中的代碼引用。
  • 該類型被聲明為public(因此可以從其他包中的代碼訪問)。

請注意在JLS文本中使用may 這表示編譯器可能會將此拒絕為無效,或者可能不會。 如果您嘗試將Java代碼構建為在源代碼級別可移植,那么這不是一個好的情況。 因此,即使一個源文件中的多個類在您的開發平台上運行,執行此操作也是不好的做法。

我的理解是,這種“拒絕許可”是一項設計決策,其目的在於使更容易在更廣泛的平台上實現Java。 如果(相反)JLS要求所有編譯器都支持包含多個類的源文件,那么在基於文件系統的平台上實現Java會存在概念性問題。

在實踐中,經驗豐富的Java開發人員根本不會錯過這樣做。 使用包,類訪問修飾符和內部或嵌套類的適當組合可以更好地完成模塊化和信息隱藏。

為什么java現在在IDE時代沒有刪除這個限制? 這不會破壞任何現有代碼(或者它會嗎?)。

現在所有代碼都是統一的。 當您看到源文件時,您知道會發生什么。 每個項目都是一樣的。 如果java要刪除這個約定,你必須重新學習你工作的每個項目的代碼結構,現在你學習它並在任何地方應用它。 我們不應該相信IDE的一切。

這不是問題的答案,而是一個數據點。

我抓住了我的個人C ++ utilty庫的標題(你可以從這里自己獲得),幾乎所有實際上都聲明類的頭文件(有些只是聲明自由函數)聲明了多個類。 我喜歡把自己想象成一個相當不錯的C ++設計師(盡管這個庫有點像一個地方 - 我是它唯一的用戶),所以我建議至少對於C ++來說,同一個文件中的多個類是正常的甚至是良好的做法。

它允許從Foobar.class到Foobar.java的更簡單的啟發式方法。

如果Foobar可能在任何Java文件中,那么您就會遇到映射問題,這可能最終意味着您必須對所有Java文件進行全面掃描才能找到該類的定義。

就個人而言,我發現這是一個奇怪的規則,結合在一起導致Java應用程序可以變得非常大並且仍然很堅固。

單個文件中可以有許多公共類。 但是,每個文件的頂級類。 每個文件可以有多個公共內部/嵌套類。

我想你喜歡這個鏈接 - 一個java文件可以有多個類嗎?

實際上,它是根據Java語言規范(第7.6節,第209頁)的可選限制,但后面是Oracle Java編譯器作為強制限制。 根據Java語言規范,

當包存儲在文件系統(第7.2.1節)中時,如果在由類型名稱加上名稱的文件中找不到類型,主機系統可以選擇強制執行編譯時錯誤的限制。如果滿足以下任一條件,則為擴展名(例如.java或.jav):

  • 該類型由聲明類型的包的其他編譯單元中的代碼引用。
  • 該類型被聲明為public(因此可以從其他包中的代碼訪問)。

這種限制意味着每個編譯單元最多只能有一個這樣的類型。 這種限制使Java編譯器可以輕松地在包中找到命名類。

實際上,許多程序員選擇將每個類或接口類型放在它自己的編譯單元中,無論它是公共的還是由其他編譯單元中的代碼引用。

例如,公共類型wet.sprocket.Toad的源代碼可以在wet / sprocket目錄中的Toad.java文件中找到,相應的目標代碼可以在同一目錄中的Toad.class文件中找到。

為了得到更清晰的圖片,我們假設在同一個源文件中有兩個公共類公共類A和公共類B,而A類引用了尚未編譯的類B.我們正在編譯(編譯 - 鏈接 - 加載)類A現在,當鏈接到B類編譯器時,將強制檢查當前包中的每個* .java文件,因為類B沒有它的特定B.java文件。 所以在上面的例子中,編譯器找到哪個類位於哪個源文件以及主方法所在的類中有點費時。 因此,為每個源文件保留一個公共類的原因是實際上使編譯過程更快,因為它可以在鏈接(導入語句)期間更有效地查找源文件和編譯文件。 我們的想法是,如果您知道類的名稱,就知道每個類路徑條目應該在哪里找到它,並且不需要索引。

而且,一旦我們執行我們的應用程序,JVM默認會查找公共類(因為沒有限制,可以從任何地方訪問),並且還在該公共類中查找public static void main(String args[]) 公共類充當從Java應用程序(程序)的JVM實例開始的初始類。 因此,當我們在程序中提供多個公共類時,編譯器本身會通過拋出錯誤來阻止您。 這是因為稍后我們不能將JVM混淆為哪個類是它的初始類,因為只有一個帶有public static void main(String args[])public static void main(String args[])類是JVM的初始類。

您可以閱讀有關“ 為什么單個Java源文件不能具有多個公共類”的更多信息

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM