溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

基于java類路徑classpath和包的示例分析

發(fā)布時(shí)間:2021-07-23 11:06:13 來源:億速云 閱讀:111 作者:小新 欄目:編程語言

這篇文章主要為大家展示了“基于java類路徑classpath和包的示例分析”,內(nèi)容簡而易懂,條理清晰,希望能夠幫助大家解決疑惑,下面讓小編帶領(lǐng)大家一起研究并學(xué)習(xí)一下“基于java類路徑classpath和包的示例分析”這篇文章吧。

類路徑(classpath)

java編譯器編譯.java文件和java虛擬機(jī)執(zhí)行.class文件時(shí)的路徑和寫法不一樣。

在沒有設(shè)置任何classpath環(huán)境變量的情況下,javac可以編譯全路徑的.java文件。例如:

javac d:\myjava\HelloWorld.java

編譯后,在.java同路徑目錄下生成class文件。

默認(rèn)java虛擬機(jī)要從classpath環(huán)境變量的路徑中搜索class文件去執(zhí)行,對于java虛擬機(jī)來說,這不是類文件,而是類。它只有類路徑,而沒有文件系統(tǒng)路徑。而classpath環(huán)境變量正是為java虛擬機(jī)提供搜索類路徑的環(huán)境。注意,虛擬機(jī)不會遞歸搜索classpath定義的路徑。

也就是說,上面的java文件可以正確編譯,但卻不能執(zhí)行。但如果將classpath設(shè)置為".;d:\myjava\",則java虛擬機(jī)將先從當(dāng)前路徑搜索,再從d:\myjava下搜索class文件。

于是上面的HelloWorld.java編譯后,可以直接執(zhí)行:

java HelloWorld

或者切換到d:\myjava目錄下,執(zhí)行java HelloWorld。

但下面則是錯誤的方式,最后雖然能正確編譯NewDir.java,但在執(zhí)行時(shí),將搜索當(dāng)前目錄(d:\myjava)下是否有NewDir.class,再搜索d:\myjava下是否有NewDir.class,但不會遞歸到子目錄newdir中去搜索class文件。

d:\
cd myjava
javac newdir\NewDir.java
java NewDir

再例如,在d:\myjava\hello下有兩個java源文件,它們的內(nèi)容分別如下:

d:\myjava\hello
 Cat.java
 Dog.java
Cat.java
=========================
public class Cat {
}
Dog.java
=========================
public class Dog {
 public static void main(String [] args) {
  Cat c = new Cat();
 }
}

其中Dog類中直接new了另一個文件中Cat類的對象,無論是編譯還是運(yùn)行,這都是能成功的,因?yàn)閖avac編譯器編譯Dog.java時(shí)會自動從classpath指定的路徑下搜索Cat.class,正好這能搜索到,且該類又是public類,因此編譯成功。

總之,要明確的是javac編譯器搜索的是文件路徑,和環(huán)境變量classpath無關(guān)。而java虛擬機(jī)搜索的是類文件,嚴(yán)格地說是類,搜索路徑由環(huán)境變量classpath決定,且有先后順序。

更多的類路徑說明,見下面的"包"。

包(package)

包是類的集合。在java源文件的第一行(不包括注釋行或空行)寫上package關(guān)鍵字并給定包名,即可將該類文件放到包中。

例如,d:\myjava\Cat.java文件:

package com.longshuai.home;
public class Cat {
 public static void main(String[] args) {
  System.out.println("com.longshuai.home.Cat");
 }
}

這表示將Cat類放在com.longshuai.home包中。包應(yīng)該以反轉(zhuǎn)后的域名取名,防止包重名沖突,當(dāng)然,這是非必須的。

對于沒有使用package指令的源文件,在編譯時(shí)其內(nèi)的類都會默認(rèn)當(dāng)作"裸體類"。

java管理包的方法是以對應(yīng)包名的目錄層次管理的,例如上面的com.longshuai.home包,應(yīng)該將該class文件放在com/longshuai/home(如果是windows,則反斜線)下,即com/longshuai/home/Cat.class。

javac在編譯時(shí)從路徑上搜索文件。例如,將這個Cat.java放到com/longshuai/home下。執(zhí)行時(shí)java虛擬機(jī)從classpath搜索要加載的類文件,而加載類的方式是使用"."連接各類名。所以編譯這個文件和java虛擬機(jī)執(zhí)行這個文件時(shí)的方法分別是:

javac com/longshuai/home/Cat.java
java com.longshuai.home.Cat

注意,嵌套的包之間沒有任何關(guān)系,例如java.util包和java.util.jar包沒有任何依賴關(guān)系。

使用包中的類和導(dǎo)入包(import)

在某個java源文件中,無法直接使用其他文件中的類,除非要使用的這個類正好能被classpath的路徑搜索到。要引用非classpath下的其他類,只能將其添加到classpath或者裝入package中,然后引用包中的類。

引用包中類可以通過指定包名的方式引用來引用。例如:

com.longshuai.home.Cat c = new com.longshuai.home.Cat();

但顯然這很不方便??梢栽趈ava源文件的前幾行(但在package命令的后面)使用import指令導(dǎo)入需要使用的包中的類。例如導(dǎo)入Cat類,這樣就可以直接使用該類了:

import com.longshuai.home.Cat;
Cat c = new Cat();

導(dǎo)入包時(shí)可以在尾部使用星號"*"通配導(dǎo)入的所有類,只能在尾部使用"*",因?yàn)?quot;*"匹配的是類名,而不是包名。也因此,不能在非結(jié)尾處使用"*"號來表示導(dǎo)入其他包中的類,例如:

import com.longshuai.home.*; //導(dǎo)入com.longshuai.home包中的所有類
import com.longshuai.*;  //導(dǎo)入com.longshuai包中所有類,但不會導(dǎo)入com.longshuai.home中的類,
        //因?yàn)殡m然層次之間有嵌套,但這些包沒有任何關(guān)系
import com.*.*;    //這是錯誤的寫法

如果導(dǎo)入的包中有同名的類,則在引用同名類的時(shí)候會產(chǎn)生沖突錯誤,例如java.util和java.sql包中都有Date類,

import java.util.*;
import java.sql.*;
public class Test {
 public static void main(String [] args) {
  Date today = new Date();
 }
}

編譯:

javac Test.java
Test.java:11: 錯誤: 對Date的引用不明確
  Date today = new Date();
  ^
 java.sql 中的類 java.sql.Date 和 java.util 中的類 java.util.Date 都匹配
Test.java:11: 錯誤: 對Date的引用不明確
  Date today = new Date();
       ^
 java.sql 中的類 java.sql.Date 和 java.util 中的類 java.util.Date 都匹配
2 個錯誤

這時(shí)可以顯式導(dǎo)入Date類,或者在使用Date類的時(shí)候指定包名。也就是說下面兩種方法都正確:

//方法一:
import java.util.*;
import java.sql.*;
import java.util.Date;
//方法二:
import java.util.*;
import java.sql.*;
public class Test {
 public static void main(String [] args) {
  java.util.Date today = new java.util.Date();
 }
}

除了可以導(dǎo)入包中的類,還可以靜態(tài)導(dǎo)入包中類中的靜態(tài)方法和靜態(tài)變量,只需加上static關(guān)鍵字并指定要導(dǎo)入的內(nèi)容即可。例如:

import static java.lang.System.*;
import static java.lang.System.out;

靜態(tài)導(dǎo)入方法后,就可以省略前綴,例如:

import static java.lang.System.out;
public class ClassName {
 public static void main() {
  out.println("HelloWorld");//等價(jià)于System.out.println("HelloWorld");
 }
}

將package歸檔成jar包

java虛擬機(jī)可以直接識別jar包??梢詫ackage名稱對應(yīng)的路徑使用jar命令歸檔成jar包。jar命令使用說明如下:

jar
用法: jar {ctxui}[vfmn0PMe] [jar-file] [manifest-file] [entry-point] [-C dir] files .
..
選項(xiàng):
 -c 創(chuàng)建新檔案
 -t 列出檔案目錄
 -x 從檔案中提取指定的 (或所有) 文件
 -u 更新現(xiàn)有檔案
 -v 在標(biāo)準(zhǔn)輸出中生成詳細(xì)輸出
 -f 指定檔案文件名
 -m 包含指定清單文件中的清單信息
 -n 創(chuàng)建新檔案后執(zhí)行 Pack200 規(guī)范化
 -e 為捆綁到可執(zhí)行 jar 文件的獨(dú)立應(yīng)用程序
  指定應(yīng)用程序入口點(diǎn)
 -0 僅存儲; 不使用任何 ZIP 壓縮
 -P 保留文件名中的前導(dǎo) '/' (絕對路徑) 和 ".." (父目錄) 組件
 -M 不創(chuàng)建條目的清單文件
 -i 為指定的 jar 文件生成索引信息
 -C 更改為指定的目錄并包含以下文件
如果任何文件為目錄, 則對其進(jìn)行遞歸處理。
清單文件名, 檔案文件名和入口點(diǎn)名稱的指定順序
與 'm', 'f' 和 'e' 標(biāo)記的指定順序相同。

例如,將當(dāng)前目錄下的a.class和b.class打包到test.jar中:

jar cvf test.jar a.class b.class

查看jar包中的文件列表,會遞歸顯示:

jar -tf test.jar
META-INF/
META-INF/MANIFEST.MF
jiecheng.class

例如,將com目錄歸檔到d:\dp.jar中。

jar cvf d:\dp.jar com/
已添加清單
正在添加: com/(輸入 = 0) (輸出 = 0)(存儲了 0%)
正在添加: com/longshuai/(輸入 = 0) (輸出 = 0)(存儲了 0%)
正在添加: com/longshuai/home/(輸入 = 0) (輸出 = 0)(存儲了 0%)
正在添加: com/longshuai/home/Bird.class(輸入 = 420) (輸出 = 291)(壓縮了 30%)
正在添加: com/longshuai/home/Bird.java(輸入 = 136) (輸出 = 100)(壓縮了 26%)
正在添加: com/longshuai/home/Cat.class(輸入 = 417) (輸出 = 289)(壓縮了 30%)
正在添加: com/longshuai/home/Cat.java(輸入 = 134) (輸出 = 99)(壓縮了 26%)

有了jar文件,就可以直接設(shè)置classpath的路徑為jar文件名,這樣在搜索類文件時(shí)就會直接從jar文件內(nèi)搜索。例如classpath設(shè)置為:

.;d:\myjava;d:\dp.jar

類搜索機(jī)制

在java虛擬機(jī)搜索類文件時(shí),除了classpath環(huán)境變量指定的路徑,還會先搜索兩個默認(rèn)的路徑:jre/lib和jre/lib/ext下的jar文件中似乎否有待搜索的類。

例如,當(dāng)classpath設(shè)置為".;d:\myjava;d:\myjar.jar"時(shí),要搜索com.longshuai.com.Cat類文件:

(a).先搜索jre/lib和jre/lib/ext下的jar文件;

(b).再搜索當(dāng)前目錄下是否有com\longshuai\com\Cat.class;

(c).再搜索d:\myjava\Cat.class;

(d).搜索d:\myjar.jar文件中是否有com.longshuai.com.Cat類。

如果在某個java源文件中引用了某個類,則在編譯時(shí),將通過以下幾種方式判斷該類是否合理有效:

(1).搜索導(dǎo)入的包類中是否包含該類。

(2).搜索隱式導(dǎo)入的java.lang包,該包是默認(rèn)導(dǎo)入的。

(3).當(dāng)前文件中是否定義了該類。

(4).按照類路徑的搜索規(guī)則((a)-(d))搜索其中是否有該類。

繼承

類與類之間能體現(xiàn)"什么是什么"的語義邏輯,就能實(shí)現(xiàn)類的繼承。例如,貓是動物,那么貓類可以繼承動物類,而貓類稱為子類,動物類稱為父類。

子類繼承父類后,子類就具有了父類所有的成員,包括成員變量、方法。實(shí)際上在內(nèi)存中,new子類對象時(shí),heap中劃分了一部分區(qū)域存放從父類繼承來的屬性。例如,new parent得到的區(qū)域A,new child得到的區(qū)域B,區(qū)域A在區(qū)域B中。

子對象中之所以包含父對象,是因?yàn)樵趎ew子對象的時(shí)候,首先調(diào)用子類構(gòu)造方法構(gòu)造子對象,在開始構(gòu)造子對象的時(shí)候又首先調(diào)用父類構(gòu)造方法構(gòu)造父對象。也就是說,在形成子對象之前,總是先形成父對象,然后再慢慢的補(bǔ)充子對象中自有的屬性。具體內(nèi)容見"繼承時(shí)構(gòu)造方法的重寫super()"。

基于java類路徑classpath和包的示例分析

子類不僅具有父類的成員,還具有自己獨(dú)有的成員,例如有自己的方法、自己的成員變量。子類、父類中的成員名稱不同時(shí)這很容易理解,但它們也可能是同名的。如果子類中有和父類繼承的同名方法,例如父類有eat()方法,子類也有eat()方法,則這可能是方法的重寫(見下文)。如果子類中的成員變量和父類的成員變量同名,則它們是相互獨(dú)立的,例如父類有name屬性,子類還自己定義了一個name屬性,這是允許的,因?yàn)榭梢苑謩e使用this和super來調(diào)用它們。

繼承類時(shí)使用extends關(guān)鍵字。繼承時(shí),java只允許從一個父類繼承。

class Person {
 String name;
 int age;
 void eat() { System.out.println("eating...");}
 void sleep() {System.out.println("sleep...");}
}
class Student extends Person {
 int studentID;
 Student(int id,String name,int age) {
  this.name = name;
  this.age = age;
  this.studentID = id;
 }
 void study() {System.out.println("studing...");}
}
public class Inherit {
 public static void main(String[] args) {
  Student s1 = new Student(1,"Malongshuai",23);
  System.out.println(s1.studentID+","+s1.name+","+s1.age);
  s1.eat();
  s1.sleep();
  s1.study();
 }
}

以上是“基于java類路徑classpath和包的示例分析”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內(nèi)容對大家有所幫助,如果還想學(xué)習(xí)更多知識,歡迎關(guān)注億速云行業(yè)資訊頻道!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI