A. java只有一個public類
因為java程序是從一個public類的main( )函數開始執行的,編譯器在編譯時,針對一個java源代碼文件(編譯單元)只會接受一個public類。
每個編譯單元只有單一的公共介面,用public類來表現,如果很多PUBLIC 類,那程序從何運行?這個單一的公共介面可以包含多個支持包訪問許可權的類。如果有一個以上的public 類,編譯器就會報錯。同時,public類的名稱必須完全與含有該編譯單元的文件名完全一致。如果不一致,也會導致將編譯錯誤。
不過,雖然不是很常用,但編譯單元內完全不帶public類也是可能的。
(1)編譯單元內可以不帶擴展閱讀
java源文件中只能有一個public類驗證
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
B. 在C/C++中,什麼叫編譯單元
可以這樣的理解:
編譯單元
當一個c或cpp文件在編譯時,預處理器首先遞歸包含頭文件,
形成一個含有所有 必要信息的單個源文件,這個源文件就是一個編譯單元。
這個編譯單元會被編譯成為一個與cpp 文件名同名的目標文件 。
連接程序把不同編譯單元中產生的符號聯系起來,構成一個可執行程序。
C. 如何理解和使用Java package包
Java中的一個包就是一個類庫單元,包內包含有一組類,它們在單一的名稱空間之下被組織在了一起。這個名稱空間就是包名。可以使用import關鍵字來導入一個包。例如使用import java.util.*就可以導入名稱空間java.util包裡面的所有類。所謂導入這個包裡面的所有類,就是在import聲明這個包名以後,在接下來的程序中可以直接使用該包中的類。例如:
[java] view plain
import java.util.*
public class SingleImport
{
public static void main(Strin[] args)
{
ArrayList list=nwe ArrayList();
}
}
這里ArrayList就是java.util包中的一個類,但是由於對程序使用了import關鍵字載入了java.util包,所以這里並沒有見到對ArrayList類的定義和聲明,也沒有見到該類前面有什麼限定名,就可以直接使用這個類。
我們之所以要導入包名,就是要提供一個管理名稱空間的機制。我們知道,如果有兩個類A類和B類都含有一個具有相同特徵標記(參數列表)的方法f(),即便在同一段代碼中同時使用這兩個方法f(),也不會發生沖突,原因就在於有兩個不同的類名罩在前面作為限定名,所以兩個方法即便同名也不回發生沖突。但是如果類名稱相互沖突又該怎麼辦呢?假設你編寫了一個Apple類並安裝到了一台機器上,而該機器上已經有一個其他人編寫的Apple類,我們該如何解決呢?因為你如果想弄清楚一台機器上到底已經安裝了那些類,並不是一件很容易的事情,所以名字之間總是有存在潛在的沖突的可能。在Java中對名稱空間進行完全控制並為每個類創建唯一的標識符組合就成為了非常重要的事情。如果你要編寫對於同一台機器上共存的其他Java程序友好的類庫或程序的話,就需要考慮如何防止類名稱之間的沖突問題。
當編寫一個Java源代碼文件時,此文件通常被稱為編譯單元。每個編譯單元都必須有一個後綴名.java,而在編譯單元內有且僅有一個public類,否則編譯器就不會接受。該public類的名稱必須與文件的名稱相同(包括大小寫,但不包括後綴名.java)。如果在該編譯單元之中還有額外的類的話,那麼在包之外的世界是無法看見這些類的,因為它們不是public類,而且它們主要用來為主public類提供支持。
當編譯一個.java文件(即一個編譯單元)時,在.java文件中的每個類都會有一個輸出文件,而該輸出文件的名稱與.java文件中每個類的名稱相同,只是多了一個後綴名.class。因此在編譯少量.java文件之後,會得到大量的.class文件。每一個.java文件編譯以後都會有一個public類,以及任意數量的非public類。因此每個.java文件都是一個構件,如果希望許許多多的這樣的構件從屬於同一個群組,就可以在每一個.java文件中使用關鍵字package。而這個群組就是一個類庫。
如果使用package語句,它必須是.java文件中除注釋以外的第一句程序代碼。如果在文件的起始處寫:
package fruit;
就表示你在聲明該編譯單元是名為fruit的類庫的一部分,或者換句話說,你正在聲明該編譯單元中的public類名稱是位於fruit名稱的保護傘下,由fruit名稱罩著。任何想要使用該public類名稱的人都必須指定全名或者與fruit結合使用關鍵字import。
例如,假設文件的名稱是Apple.java,這就意味著在該文件中有且僅有一個public類,該類的名稱必須是Apple(注意大小寫):
[java] view plain
package fruit;
public class Apple
{
//...
}
上面的代碼已經將Apple類包含在了fruit包中,現在如果有人想使用Apple或者是fruit中的任何其他public類,就必須使用關鍵字import來使fruit中的名稱可用。
[java] view plain
import fruit.*;
public class ImportApple
{
public static void main(String[] args)
{
Apple a=new Apple();
}
}
或者使用完整限定名稱:
[java] view plain
public class QualifiedApple
{
public static void main(String[] args)
{
fruit.Apple a=new fruit.Apple();
}
}
顯然使用關鍵字import使代碼更加簡潔。
作為一名程序員,我們應該牢記:package和import關鍵字允許做的是將單一的全局名稱空間分割成各自獨立封閉的名稱空間,使得無論多少人使用Internet以及Java開始編寫類,都不會出現與我們的類名稱相沖突的問題,因為我們的類是被封閉在我們自己定義的獨立的名稱空間裡面的,而非在公共的全局名稱空間裡面。
到這里也許你會發現,其實所謂關鍵字package打包從未將被打包的東西包裝成一個單一的文件,並且一個包可以由許多.class文件構成,這就存在將兩個名稱相同的類打進一個包中的可能。為了避免這種情況的發生,一種合乎邏輯的做法就是將特定的所有.class文件都置於一個目錄下。也就是說利用操作系統的層次化的文件結構來解決這一問題。這是Java解決混亂問題的一種方式(這里暫且先不討論JAR包工具)。
將所有的文件收入一個子目錄還可以解決另外兩個問題:一、怎樣創建獨一無二的名稱;二、怎樣查找有可能隱藏於目錄結構中某處的類。
這些任務是通過將.class文件所在的路徑位置編碼稱package的名稱來實現的。
按照慣例,package名稱的第一部分是類的創建者的反順序的Internet域名。為什麼要用Internet域名呢?因為如果你遵照慣例,Internet域名應該是獨一無二的,因此你的package名稱也將是獨一無二的,也就是前面提到的我們自定義的獨立封閉的名稱空間將是獨一無二的,這樣就不會出現名稱沖突的問題了。當然,如果你沒有自己的域名,你就得構造一組不大可能與他人重復的組合(例如你的姓名),來創立獨一無二的package名稱。如果你打算發布你的Java程序代碼,稍微花費些代價去取得一個域名還是很有必要的。
另外,如果你的Java程序代碼只是在本地計算機上運行,你還可以把package名稱分解為你機器上的一個目錄。所以當Java程序運行並且需要載入.class文件的時候,它就可以根據package名稱確定.class文件在目錄上的所處位置。
程序在運行的時候具體是如何確定.class文件位置的呢?
來看看Java解釋器的運行過程吧:首先,找出環境變數CLASSPATH(可以通過操作系統來設置)。CLASSPATH包含一個或多個目錄,用作查找.class文件的根目錄。從根目錄開始,解釋器獲取包名稱並將每個句點替換成反斜杠,以從CLASSPATH根中產生一個路徑(例如,package fruit.Apple就變成為fruit/Apple或fruit/Apple或其他,這將取決於操作系統)。得到的路徑會與CLASSPATH中的各個不同的根目錄路徑相連接以獲得一個完整的目錄路徑,解釋器就在這些目錄中查找與你所需要的類名稱相同的.class文件。(此外,解釋器還會去查找某些涉及Java解釋器所在位置的標准目錄。)
為了理解這一點,以域名Food.net為例。把它的順序倒過來,並且全部轉換為小寫,net.food就成了我們創建類的一個獨一無二的名稱空間。如果我們決定再創建一個名為fruit的類庫,我們可以將該名稱進一步細分,於是得到一個包名如下:
package net.food.fruit;
現在,這個包名稱就可以用作下面Apple這個文件的名稱空間保護傘了:
[java] view plain
package net.food.fruit;
public class Apple
{
public Apple()
{
System.out.println("net.food.fruit.Apple");
}
}
這個文件可能被置於計算機系統中的如下目錄中:
C:/DOC/JavaT/net/food/fruit
之所以要放在這個目錄下面是因為前面提到的,便於系統通過CLASSPATH環境變數來找到這個文件。沿著此路徑往回看就能看到包名net.food.fruit,但是路徑的前半部分怎麼辦呢?交給環境變數CLASSPATH吧,我們可以在計算機中將環境變數CLASSPATH設置如下:
CHASSPATH=.;D:/JAVA/LIB;C:/DOC/JavaT
CLASSPATH可以包含多個可供選擇的查詢路徑。每個路徑都用分號隔開,可以看到,上面這個CLASSPATH環境值的第三個路徑就是我們前面文件的根目錄。如前所述,Java解釋器將首先找到這個根目錄C:/DOC/JavaT,然後將其與包名net.food.fruit相連接,連接的時候將包名中的句點轉換成斜杠,就得到完整的class文件路徑C:/DOC/JavaT/net/food/fruit。
需要補充說明的一點,這里CLASSPATH環境變數關照的是package中的class文件,如果關照的是JAR包中的class文件,則會有一點變化,即,必須在CLASSPATH環境變數路徑中將JAR文件的實際名稱寫清楚,而不僅僅是指明JAR包所在位置目錄。可以想像,因為JAR包所在目錄位置上可能存在很多別的JAR包,而我們需要使用的那個class文件只會存在於其中一個JAR包裡面,因此可以這樣理解,這里JAR包實際上也充當了一級文件目錄的角色,因此要在CLASSPATH環境變數中寫清楚JAR包文件名。例如如果Apple文件存在於名為fruit.jar的JAR文件中,則CLASSPATH應寫作:
CLASSPATH=.;D:/JAVA/LIB;C:/DOC/JavaT/net/food/fruit.jar
一旦路徑得以正確建立,下面的文件就可以放於任何目錄之下:
[java] view plain
import net.food.fruit.*;
public class LibTest
{
public static void main(String[] args)
{
Apple a=new Apple();
}
}
當編譯器碰到fruit庫的import語句時,就開始在CLASSPATH所指定的目錄中查找,查找過程中分別將CLASSPATH中設定的各項根目錄與包名轉換來的子目錄net/food/fruit相連接,在連接後的完整目錄中查找已編譯的文件(即class文件)找出名稱相符者(對Apple而言就是Apple.class)。找到了這個文件即匹配到了Apple類。
D. android的src下面可以包含多個package嗎
當然可以,src目錄下的package用戶可以隨意創建。
1.package就是Java中的包,一個包就是一個類庫單元,包內包含有一組類,它們在單一的名稱空間之下被組織在了一起。這個名稱空間就是包名。可以使用import關鍵字來導入一個包。例如使用import java.util.*就可以導入名稱空間java.util包裡面的所有類。所謂導入這個包裡面的所有類,就是在import聲明這個包名以後,在接下來的程序中可以直接使用該包中的類。
2.之所以要導入包名,就是要提供一個管理名稱空間的機制。如果有兩個類A類和B類都含有一個具有相同特徵標記(參數列表)的方法f(),即便在同一段代碼中同時使用這兩個方法f(),也不會發生沖突,原因在於是不同的類對象調用,所以兩個方法即便同名也不會發生沖突。
3.當編寫一個Java源代碼文件時,此文件通常被稱為編譯單元。每個編譯單元都必須有一個後綴名.java,而在編譯單元內有且僅有一個public類,否則編譯器就不會接受。該public類的名稱必須與文件的名稱相同(包括大小寫,但不包括後綴名.java)。如果在該編譯單元之中還有額外的類的話,那麼在包之外的世界是無法看見這些類的,因為它們不是public類,而且它們主要用來為主public類提供支持。
4. 當編譯一個.java文件(即一個編譯單元)時,在.java文件中的每個類都會有一個輸出文件,而該輸出文件的名稱與.java文件中每個類的名稱相同,只是多了一個後綴名.class。因此在編譯少量.java文件之後,會得到大量的.class文件。每一個.java文件編譯以後都會有一個public類,以及任意數量的非public類。因此每個.java文件都是一個構件,如果希望許許多多的這樣的構件從屬於同一個群組,就可以在每一個.java文件中使用關鍵字package。而這個群組就是一個類庫。
E. C語言中的存儲類說明符有哪些各自的含義如何
inline int foo(int a, int b) { return a + b; }int main(int argc, char *argv[]){return(1,2);
*ANSI C, ISO/IEC C89/C90:標准中沒有inline關鍵字.
*GNU C89/C90:
1、static inline:函數名標識符的作用域為當前編譯單元(translation unit),允許其他編譯單元中有重名定義. 這里的inline建議編譯器,函數在被調用時可以直接展開函數體,但是否展開取決於編譯器.(譬如,如果優化級別為-O0,則必須按函數地址調用,此時編譯器會忽略inline請求,將函數編譯為普通函數;或者,出現了遞歸調用,編譯器也無法內聯這個函數)
2、inline:在當前編譯單元內,和static inline語義相同,都是建議編譯器在當前編譯單元內展開函數體(是否展開取決於編譯器). 但同時編譯器會對該函數生成一份普通函數的代碼,在其他編譯單元內可以調用,與普通的extern函數調用無異.
3、extern inline:相當詭異. 這樣的函數定義只為內聯而提供. 如果強行用普通函數調用方式調用該函數(譬如,優化級別為-O0,或者按函數指針調用),則鏈接器會認為存在另一個同名的普通函數. 如果沒有這個同名普通函數的定義,則鏈接器會報告找不到符號.
*ISO/IEC C99/C11:
1、static inline:和GNU C89/C90中的語義完全相同.
2、inline:很類似GNU C89/C90中的extern inline. 標准文檔中的解釋相當晦澀:允許(但不要求)編譯器在當前編譯單元內展開函數體(原文的描述是「相比正常的函數調用機制,讓內聯函數調用盡可能快」,而文檔下面的腳注中提到,可能的選擇是「內聯替換」,見ISO/IEC 9899:1999或ISO/IEC 9899:2011),是否內聯由編譯器設計者自行決定,同時也允許外部存在同名的普通函數定義. 經測試最新版本的Clang和GCC在標准-std=c99和-std=c11下會在可以內聯的情況下(例如優化級別為-O2)採用內聯版本.
3、但標准文檔中同時也規定了,若在函數聲明中加入extern,則相應的內聯函數定義成為所謂的外部定義,行為和GNU C89/C90的inline相同:在當前編譯單元中建議編譯器展開函數體,同時生成一份普通函數的代碼,在其他編譯單元中也可調用.
4、extern inline:標准文檔中未見extern inline的定義.
*GNU C99/C11:採用與ISO/IEC C99/C11相同的語義.
最新版本的Clang和GCC默認均採用GNU C11標准,因此會出現不優化代碼時找不到內聯函數符號的錯誤.
F. java中為什麼這么用public修飾類會報錯
因為public類只能有一個,你的main方法所在的類已經寫public了
G. 編譯單元的介紹
當一個c或cpp文件在編譯時,預處理器首先遞歸包含頭文件,形成一個含有所有必要信息的單個源文件,這個源文件就是一個編譯單元。
H. 在同一編譯單元用extern和不用有什麼區別
對函數來說沒區別,不用extern的函數默認就是extern的,即其他文件也可以調用這個函數;但對變數來說有區別,不用extern聲明變數的話,變數默認是static的,其他文件不能使用這個變數。那麼如果所有函數和變數都只放在一個文件里進行編譯,用不用extern就沒有任何區別了。
I. 為什麼JAVA文件中只能含有一個Public類
每個編譯單元都有單一的公共介面,用public類來表現。該介面可以按要求包含眾多的支持包訪問許可權的類。如果在某個編譯單元內有一個以上的public類,編譯器就會給出錯誤信息。
一個Java源文件中可以有多個類,但只能有一個public的類,並且public的類名必須與文件名相一致。一個文件中可以只有非public類,如果只有一個非public類,此類可以跟文件名不同。
(9)編譯單元內可以不帶擴展閱讀:
JAVA類中主要包含屬性、方法、構造方法、塊以及內部類。
屬性用來定義對象的數據;
方法用來定義對象的行為;
構造方法可以用來創建對象;
塊能夠用來在類載入時執行操作或者在每次實例化前執行通用操作;
內部類作為類的一個成員存在,能夠訪問外部類的屬性和方法。
類是對象的模板,使用類往往都需要首先對類進行實例化,即創建對象。要創建對象必須使用new關鍵字調用構造方法(constructor)才能完成,構造方法中往往對屬性進行實例化,也可以實現其他必要的功能,如讀取屬性文件等。
構造方法的作用是用來創建對象,使用new關鍵字調用。構造方法的名字必須與類的名字相同,並且大小寫敏感,同時構造方法不能聲明返回值類型,可以使用任意一種訪問修飾符,但是不能使用其他修飾符進行修飾,如static、final、abstract等修飾符都可以修飾構造方法。
J. JAVA 關於封裝的這個問題 為什麼會報錯
你好,很高興回答你的問題。
主要問題是兩個。
第一,一個java文件中可以有多個類,但是只能有一個類是public,並且這個類的類名需要與文件名一致。
第二,注意大括弧,雖然if塊內只有一個語句時,可以省略大括弧,但是還是不要省略,容易出錯,比如你這里。
另外提示一下,縮進需要注意,雖然不影響運行,但是會影響閱讀。