摘要:比如說,就是復姓,名字為的類別則是復姓,名字為的類別。先介紹的機制基本原則需要將類文件切實安置到其所歸屬之所對應的相對路徑下。把源代碼文件,文件和其他文件有條理的進行一個組織,以供來使用。可以使用通配符,代表某下所有的,不包括子目錄。
一些人用了一陣子的Java,可是對于 Java 的 package 跟 import 還是不太了解。很多人以為原始碼 .java 文件中的 import 會讓編譯器把所 import 的程序通通寫到編譯好的 .class 檔案中,或是認為 import 跟 C/C++ 的 #include 相似,實際上,這是錯誤的觀念。
讓我們先了解一下,Java 的 package 到底有何用處。
其實,package 名稱就像是我們的姓,而 class 名稱就像是我們的名字。package 名稱有很多 . 的,就好像是復姓。比如說 java.lang.String,就是復姓 java.lang,名字為 String 的類別;java.io.InputStream 則是復姓java.io,名字為 InputStream 的類別。
Java 會使用 package 這種機制的原因也非常明顯,就像我們取姓名一樣,光是一間學校的同一屆同學中,就有可能會出現不少同名的同學,如果不取姓的話,那學校在處理學生數據,或是同學彼此之間的稱呼,就會發生很大的困擾。相同的,全世界的 Java 類別數量,恐怕比臺灣人口還多,而且還不斷的在成長當中,如果類別不使用套件名稱,那在用到相同名稱的不同類別時,就會產生極大的困擾。幸運的是,Java 的套件名稱我們可以自己取,不像人的姓沒有太大的選擇 ( 所以有很多同名同姓的 ),如果依照 Sun 的規范來取套件名稱,那理論上不同人所取的套件名稱不會相同 ( 請參閱 "命名慣例"的相關文章 ),也就不會發生名稱沖突的情況。
可是問題來了,因為很多套件的名稱非常的長,在寫程序時,會多打好多字,花費不少時間,比如說在A.B.C文件下有Point和Circle兩個類,現在在程序中要調用:
A.B.C.Point P1=new A.B.C.Point(); A.B.C.Circle C1=new A.B.C.Circle();
實在是不美觀又麻煩.于是,Sun 想了一個辦法,就是 import. 就是在程序一開頭的時候,說明程序中會用到那些類的路徑.首先,在檔案開頭寫:
import A.B.C.Point; import A.B.C.Circle;
這兩行說明了類的路徑,所以當程序中提到Point就是指A.B.C.Point,而Circle就是指A.B.C.Circle,依此類推。于是原來的程序就變成:
Point P1=new Point(); Circle C1=new Circle();
這樣看起來是不是清爽多了呢?如果這些類別用的次數很多,那就更能體會到import 的好處了。可是這樣還是不夠,因為懶是人的天性,還是會有人覺得打太多 import 了也很浪費時間,于是 Sun 又提供了一個方法:
import A.B.C.*; /*意思就是,等一下程序中提到的沒有姓名的類別,全都包含在A.B.C這個目錄中。*/
注意點:但我們在程序中經常使用System.out這個類,為什么沒有import System.out呢,因為java.lang 這個套件實在是太常太常太常用到了,幾乎沒有程序不用它的,所以不管你有沒有寫 import java.lang;,編譯器都會自動幫你補上,也就是說編譯器只要看到沒有姓的類別,它就會自動去 java.lang 里面找找看,看這個類別是不是屬于這個套件的。所以我們就不用特別去import java.lang 了。
為甚么我一開始說 import 跟 #include 不同呢?因為 import 的功能到此為止,它不像 #include 一樣,會將檔案內容載入進來。import 只是請編譯器幫你打字,讓編譯器把沒有姓的類別加上姓,并不會把別的文件的程式碼寫進來。如果你想練習打字,可以不要使用 import,只要在用到類別的時候,用它的全部姓名來稱呼它就行了(就像例子一開始那樣),跟使用 import 完全沒有甚么兩樣。
先介紹Java的Package機制
基本原則:需要將類文件切實安置到其所歸屬之Package所對應的相對路徑下。
例如:以下面程序為例:假設此Hello.java文件在D:Java下
package A; public class Hello{ public static void main(String args[]){ System.out.println("Hello World!"); } } D:Java>javac Hello.java 此程序可以編譯通過.接著執行。 D:Java>java Hello 但是執行時,卻提示以下錯誤! Exception in thread "main" java.lang.NoClassDefFoundError: hello (wrong name: A/Hello) at java.lang.ClassLoader.defineClass0(Native Method) at java.lang.ClassLoader.defineClass(ClassLoader.java:537) at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:123) at java.net.URLClassLoader.defineClass(URLClassLoader.java:251) at java.net.URLClassLoader.access$100(URLClassLoader.java:55) at java.net.URLClassLoader$1.run(URLClassLoader.java:194) at java.security.AccessController.doPrivileged(Native Method) at java.net.URLClassLoader.findClass(URLClassLoader.java:187) at java.lang.ClassLoader.loadClass(ClassLoader.java:289) at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:274) at java.lang.ClassLoader.loadClass(ClassLoader.java:235) at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:302)
原因是我們把生成的Hello.class規定打包在D:JavaA文件中,必須在A文件中才能去運行。所以應該在D:Java目錄下建立一個A目錄,然后把把Hello.class放在它下面,執行時,可正常通過!
D:Java>java A.hello 就會輸出:Hello world!
現在介紹Java的import機制
我們在D:Java目錄下建立一個JInTian.java文件,其內容如下:
import A.Hello; public class JInTian{ public static void main(String[] args){ Hello Hello1=new Hello(); } } D:Java>javac JInTian.java 編譯成功! D:Java>java JInTian 運行成功!
也就是你在JInTian.class中成功的引用了Hello.class這個類,是通過import A.Hello來實現的,如果你沒有這句話,就會提示不能找到Hello這個類。
提示1:如果你在D:Java目錄下仍保留一個Hello.java文件的話,執行對主程序的編譯命令時仍會報錯!你自己可以試試呀!
提示2:如果你刪除D:JavaAHello.java文件的話,只留Hello.class文件,執行對主程序的編譯命令時是可以通過,此時可以不需要子程序的源代碼。
提出一個問題:如果把目錄A剪切到其它目錄,如D盤根目錄下,在A目錄如果執行編譯和執行命令呢?
很明顯,會報以下錯誤!當然了,前提條件是你沒有設置classpath路徑,其實只要沒把類搜索路徑設置到我這個位置就會出錯的!你試試吧!
由于大家對package的使用存在太多困惑,我在這里將自己對于package的使用的領悟進行一點總結:
package中所存放的文件
所有文件,不過一般分一下就分這三種
1,java程序源文件,擴展名為.java。
2,編譯好的java類文件,擴展名為.class。
3,其他文件,其他任何文件,也稱為resource
例如圖片文件,xml文件,mp3文件,avi文件,文本文件……
package是什么
package好比java用來組織文件的一種虛擬文件系統。package把源代碼.java文件,.class文件和其他文件有條理的進行一個組織,以供java來使用。package是將文件組織在一顆類似unix,linux文件系統的樹結構里面,它有一個根"/",然后從根開始有目錄和文件,目錄中也還有文件和目錄。
package怎么實現的呢?
源代碼的要求最嚴格,而一旦源代碼自己聲明了在哪個package路徑之下,class也就有了自己在哪個package下面的信息,就是那句程序開頭的"package xx.xx.xx"。有人問,為什么要有這個信息,直接放目錄結構里不就好了么?是啊,直接放目錄中確實可以找到.class和.java,但是如果我要輸出這個.class是屬于哪個package的,該怎么辦?所以我們需要在.class里面留一個package的信息。如果我們要區分同樣名稱為A.class的類怎么辦?所以我們需要在.class里面留一個package的信息。
.java文件是一個獨立的編譯單元,類似c++里面的cpp文件,但是它不需要.h文件,只要.java就足夠了,一個.java文件里面可以包含一個public的類,若干package類(package類特征是沒有任何訪問控制修飾),還有內隱類的話,則還可以包含若干protected和private的類。每個類,都會在編譯的時候生成一個獨立的.class文件,所以.java和.class不是一對一,而是一對多的關系,不過.java和public的類是一對一的。所有這些.class,都由這個.java開頭的package語句來確定自己在package中的位置。
package xx.bb.aa;
說明這個.java編譯單元中的所有類都放到xx.bb.aa這個package里面。而對應的,必須把這個.java文件放在xx目錄下bb目錄下的aa目錄里面。如果一個.java文件沒有任何package語句,那么這個.java里面的所有類都在package的"/"下面,也稱之為default package。可以看出你一般從任何java教科書上寫的第一個hello world程序的那個類是在defaultpackage里面的。有了package語句,情況就復雜一點了。這個編譯單元.java必須放在package名對應的目錄之下。而生成的class文件也要放在對應的目錄結構之下才能正常運作。
例如:
/* A.java */ package aaa.bbb.ccc; public class A{ B b=new B(); } /* B.java*/ package aaa.bbb.ccc; public class B{}
編譯時候怎么填參數呢?我根據package+文件名的格式來寫,
javac aaa.bbb.ccc.A.java
漂亮吧?可惜不工作。非要使用合法的路徑名才行:
javac aaa/bbb/ccc/A.java
但是你發現生成的class丟失了目錄結構,直接出現在當前目錄下……
最好的方式是
javac -d bin aaa/bbb/ccc/A.java
這樣就會在當前目錄的bin目錄下看到完整的目錄結構以及放置妥當的class文件。
package與classpath不得不說的事
對于java來講,所有需要的程序和資源都要以package的形式來組織和讀取。
那么classpath又是什么呢?
所有放到設定到classpath里面的東西就是package所包納的資源。classpath的寫法如同path,只是里面可以寫的一般只有zip文件、jar文件和目錄。多個元素之間用當前系統路徑分隔符間隔開了,linux上分隔符號是":",windows上是";"。classpath在java里面是被一個叫做classloader的東西所使用的,classloader顧名思義,就是load class用的,但它也可以load其它在package里面的東西。現在的java里面classloader是有階層關系的,一般我們所常接觸到的CLASSPATH環境變量,javac,java的-cp,-classpath參數所給的classpath信息是被appclassloader所使用的。而appclassloader其實是第三層的classloader,最高層的classloader叫做bootstrap classloader,它不是java寫的classloader,而是c++寫成的,第二層叫做extclassloader,默認包納是jre/lib/ext里面的classes目錄和所有jar文件作為內容。第三層才是我們命令行參數,或者不用命令行參數,用系統環境變量指定classpath的使用者app classloader,這是最基本的java se。如果是java ee,有了服務器,容器,還有更多層的classloader,他們在app classloader的更下面,例如tomcat的某web應用程序的web-inf/lib中的jar,zip和classes目錄,是app之下好幾層的classloader使用的。
你可以建立自己的classloader,都在app classloader之下,實際上tomcat本身也是這樣建立classloader的。分層的目的是為了安全,試想你加入搞了一個classloader,從網絡上讀取class,而在里面寫上格式化硬盤的代碼,人家一讀運行,那不就掛了,所以分層之后,首先從最高層讀,沒有再往下找,找到就不著了。一般java所必須的rt.jar里面的若干class,是在bootstrap classloader啟動的時候讀入的,而jmf使用的幾個jar,是在ext classloader里面讀入的。也就是說,讀入這些class的時候,我們的appclassloader還在娘胎里呢,所以你在CLASS PATH中指定rt.jar是完全愚蠢多余的。java絕對不會到這里找rt.jar,而bootstrapclassloader如果你不特別要修改,它是常量,不需要你care。
import干嗎用的?
import只是一種讓你偷點懶少打字的方法,絕對不會影響你的classpath,這點你要好好記住,沒有非用import不可的理由,用了import也不會起到類似c里面嵌入某文件內容的效果,它只是一種省事的辦法。不在classpath中的class,任你再import也無濟于事。
如果你不用import,你用ArrayList這個類,就需要寫
java.util.ArrayList。
而用了import java.util.ArrayList;的話
以后代碼中寫ArrayList就可以了,省事。import可以使用通配符,代表某package下所有的class,不包括子目錄。
import java.awt.*
不等于
import java.awt.* import java.awt.event.*
如果你要簡寫java.awt.event下和java.awt下的類,你不能偷懶,兩個都要import。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/68720.html
摘要:如何讓運行模塊文件,及其原理最新版的支持最新版幾乎所有特性,但有一個特性卻一直到現在都還沒有支持,那就是從開始定義的模塊化機制。便是使用這種方式達到運行模塊文件的目的的。 如何讓 node 運行 es6 模塊文件,及其原理 最新版的 node 支持最新版 ECMAScript 幾乎所有特性,但有一個特性卻一直到現在都還沒有支持,那就是從 ES2015 開始定義的模塊化機制。而現在我們很...
摘要:本文接上一篇樂字節關鍵字關鍵字塊。本文是接著講述垃圾回收機制和語句。一垃圾回收機制全名垃圾回收機制程序員無權調用垃圾回收器。通知運行,但是規范并不能保證立刻運行。若缺省該語句,則指定為無名包。 本文接上一篇:樂字節Java|this關鍵字、static關鍵字、block塊。本文是接著講述JavaGC垃圾回收機制、package 和 import語句。showImg(https://se...
摘要:反射機制的應用實例在泛型為的中存放一個類型的對象。工廠模式可以參考現在我們利用反射機制實現工廠模式,可以在不修改工廠類的情況下添加任意多個子類。 學習交流群:669823128java 反射 定義 功能 示例概要:Java反射機制詳解| |目錄 1反射機制是什么 2反射機制能做什么 3反射機制的相關API 通過一個對象獲得完整的包名和類名 實例化Class類對象 獲取一個對象的父類與...
閱讀 1386·2019-08-30 12:54
閱讀 1870·2019-08-30 11:16
閱讀 1613·2019-08-30 10:50
閱讀 2448·2019-08-29 16:17
閱讀 1266·2019-08-26 12:17
閱讀 1378·2019-08-26 10:15
閱讀 2387·2019-08-23 18:38
閱讀 785·2019-08-23 17:50