程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> Java的Package與Import機制之我的理解(初學者的心得)

Java的Package與Import機制之我的理解(初學者的心得)

編輯:關於JAVA

以下內容的測試條件是你的機器上,設置了path命令PATH= D:\JDK1.4\BIN;D:\JDK1.4\LIB;,可以正常執行java和Javac命令,不用設置classpath路徑的情況下。

從一個簡單的例子談談package與import機制

基本原則:為什麼需要將Java文件和類文件切實安置到其所歸屬之Package所對應的相對路徑下。

為什麼要這樣做呢?如果你在程序中,用到打包命令package,並且直接編譯和執行該程序。例如:以下面程序為例:

package a.b.c;

public class hello

{

public static void main(String args[])

{

System.out.println("Hello the world!");

}

}

此程序可以編譯通過,但是執行時,卻提示以下錯誤!

D:\my\xdj>javac hello.Java

D:\my\xdj>Java hello

Exception in thread "main" Java.lang.NoClassDefFoundError: hello (wrong name: a/

b/c/hello)

at Java.lang.ClassLoader.defineClass0(Native Method)

at java.lang.ClassLoader.defineClass(ClassLoader.Java:537)

at java.security.SecureClassLoader.defineClass(SecureClassLoader.Java:12

3)

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)

D:\my\xdj>

在xdj目錄下建立一個\a\b\c子目錄把hello.Java放在它下面,用以下命令進行編譯和執行時,可正常通過!

D:\my\xdj>javac d:\my\xdj\a\b\c\hello.Java

D:\my\xdj>Java a.b.c.hello

Hello the world!

D:\my\xdj>

再看下面另外一種情況,先讓我們在xdj目錄下建立兩個文件a.java和b.Java文件,其內容如下。

a.Java文件內容:

import a.b.c.*;

public class a

{

public static void main(String[] args)

{

b b1=new b();

b1.print();

}

}

a.Java文件內容:

package a.b.c;

public class b

{

public void print()

{

System.out.println("我是被調用子類的程序輸出呀!");

}

}

直接編譯a.Java文件時,會提示以下錯誤!

D:\my\xdj>javac a.Java

a.Java:1: package a.b.c does not exist

import a.b.c.*;

^

a.Java:6: cannot Access b

bad class file: .\b.Java

file does not contain class b

Please remove or make sure it appears in the correct subdirectory of the classpa

th.

b b1=new b();

^

2 errors

D:\my\xdj>

接下來,我們把b.java移到xdj\a\b\c\下,並把\xdj目錄下的b.java刪除掉呀!重新執行編譯指令,這次肯定可以編譯成功!你可以發現b.Java也同時被編譯過了,這就是所謂的make編譯方式。

D:\my\xdj>javac a.Java

D:\my\xdj>

提示1:如果你在\xdj目錄下仍保留一個b.Java文件的話,執行對主程序的編譯命令時仍會報錯!你自己可以試試呀!

提示2:如果你刪除\xdj\a\b\c\b.Java文件的話,保留b.class文件,執行對主程序的編譯命令時是可以通過,此地可以不需要子程序的源代碼。

提出一個問題:如果把目錄\a\b\c全部剪切到其它目錄,如D盤根目錄下,在\xdj目錄如果執行編譯和執行命令呢?

很明顯,會報以下錯誤!當然了,前提條件是你沒有設置classpath路徑,其實只要沒把類搜索路徑設置到我這個位置就會出錯的!你試試吧!

D:\my\xdj>javac a.Java

a.Java:1: package a.b.c does not exist

import a.b.c.*;

^

a.Java:6: cannot resolve symbol

symbol : class b

location: class a

b b1=new b();

^

a.Java:6: cannot resolve symbol

symbol : class b

location: class a

b b1=new b();

^

3 errors

D:\my\xdj>Java a

Exception in thread "main" Java.lang.NoClassDefFoundError: a/b/c/b

at a.main(a.Java:6)

D:\my\xdj>

解決的辦法可以用以下命令即可正常編譯和執行:

D:\my\xdj>javac -classpath d:\ a.Java

D:\my\xdj>Java -classpath d:\;a

我是被調用子類的程序輸出呀!

D:\my\xdj>

提示3:-classpath參數,缺省是以當前目錄為根基目錄的,即不帶-classpath參數的情況下。

提示4:使用java.exe還是Javac.exe,最好明確指定-classpath選項,可設置環境變量CLASSPATH即可,同時設置了-classpath參數和環境變量classpath時,會以-classpath參數為主的。如果在它們所指定的路徑或JAR文件中存有package名稱和類名稱相同的類,會引起混淆的!

如果你在D盤的根目錄生成一個打包文件a.zip,其內容目錄a\b\c\下的所有文件的話,你也可以用下面命令進行編譯和執行。

D:\my\xdj>javac -classpath d:\a.zip a.Java

D:\my\xdj>Java -classpath d:\a.zip;. a

我是被調用子類的程序輸出呀!

D:\my\xdj>

以上討論就暫告一段落吧!如果你還想進一步了解package與import機制話,哪你可以繼續往下看下去的。

深入分析package與import機制部分

不管你有沒有使用import指令,存在目前目錄下的類都會被編譯器優先采用,只要它不屬於任何package。這是因為編譯器總是先假設您所輸入的類名就是該類的全名(不屬於任何package),然後-classpath所指定的路徑中搜索屬於該類的.Java文件或.class文件,在這裡可以知道default package的角色非常特殊。

必須明確告訴編譯器我們用到哪個package下的類,導入時或在包名稱.類名稱中進行引用。導入某個包時,一定要進行-classpath路徑指定某個包的位置。你如果指定了多個路徑話,如果在一個路徑下已經找到了該包話,就優先引用該包的類。

當Java編譯器開始編譯某個類的源代碼時,首先它會做一件事情,這就是建立“類路徑引用表”,它是根據參數-classpath或classpath環境變量來建立的。如果沒有指定選項-classpath或環境變量CLASSPATH時,缺省情況下類路徑引用表只有一筆記錄,即當前的目錄(“.”)。環境變量CLASSPATH的內容會被選項-classpath所覆蓋,沒有累加效果。

當編譯器將類路徑引用表建立好之後,接著編譯器要確定它可以利用類引用表裡的數據作為相對起始路徑,找到所有用到的package。

編譯器還要完成一張名為“類引用表”與“相對類引用表”的數據結構。

整個編譯程序中package與import機制相關的部分流程如下:

開始,

建立類路徑引用表與類引用表;

如果建立成功:則類名稱解析程序:

如果已存在該類的類文件,繼續其它的編譯工作。

如果該類的文件不存在,尋找該類的源代碼文件:

如果找到,則編譯該

類的源代碼,繼續

其它的編譯工作。

此時,也可返回到

開始,make機制,

遞歸式編譯。

如果找不到,編譯

結束,發出警告

信息。

如果建立失敗:編譯結束,發出警告信息(2)。

Java動態鏈接本質研究

不管你在同一個源代碼(.java)中使用了幾個類聲明,它們都會一一編譯成.class文件,即使是內部類、匿名類都是一樣。在Java中,對於每一個類所構成的類文件,都可將它視為動態鏈接庫。

在類文件中,所有對於特寫類的操作都被轉換成類的全名。Import除了用來指引編譯器解析出正確的類名稱之外,沒有其它功能。

在運行時期,仍然用到一個與編譯器相同的程序,就是類路徑引用表的建立,而利用動態鏈接載入類文件的機制流程如下:

開始,

建立類路徑引用表,

根據類文件內部的信息,與類路徑引用表的數據合成類文件的絕對路徑。

如果找到類文件,檢查該類的類文件內部信息,是否符合相對路徑信息:

如果符合,載入該類。

如果不符合,執行錯誤,發出

Exception信息。

如果找不到類文件,則執行錯誤,發出Exception信息。

最後,需要說明的是,在java中提供許多的類包,Java語言中將完成與計算機底層相關的輸入輸出、常用的數據類型轉換等功能的函數封裝在包中。如果你的程序提示找不到這樣基礎包的話,你就可以用參數-classpath或環境變量classpath進行指定位置來解決此類問題!

後面寫的有點亂呀!不知道你能否理解呀!不過相信你看完我對package與import的討論後,應該會有所收獲的。如果你還有任何關於package與import的疑問的話,可以和我一起討論和交流呀!我的郵箱是:[email protected]

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved