Java 包
當(dāng)我們的程序規(guī)模越來越大,類的數(shù)量也會隨之增多,數(shù)量繁多的類會造成項目的混亂,不易于維護(hù)管理。本小節(jié)所介紹的包就是為了將類分類而產(chǎn)生的,我們可以使用包讓程序結(jié)構(gòu)更加清晰且易于管理。本小節(jié)將會學(xué)習(xí)到什么是包,如何聲明包,包作用域以及包的命名規(guī)范等知識點。
1. 概述
1.1 什么是包
包是一個命名空間,它可以將類和接口進(jìn)行分組。
從概念上講,我們可以將包看作是計算機上的不同文件夾。例如,我們可以將圖片保存在一個文件夾中,將視頻保存在另一個文件夾中。
1.2 為什么需要包
正如我們在前言中所提到的,當(dāng)程序規(guī)模越來越大,類的數(shù)量也會隨之增多。使用包將這些類分組后,可以讓類更易于查找和使用,也可以避免命名沖突,還可以控制訪問。
易于查找和使用很容易理解,試想我們電腦的某一個文件夾中,存放著成百上千的各類文件,即使使用搜索功能都不能迅速定位到我們想要的文件,而將這些文件按照功能或特點分類存入到不同的文件夾下,就可以大大提高我們查找和使用的效率。對于 Java 語言的類也是同樣的道理。
對于命名沖突,我們來看實際開發(fā)中的一個例子:一個 Java 工程由 3 個程序員協(xié)同開發(fā),程序員 A
寫了一個工具類 Util
,程序員 B
也寫了一個工具類 Util
,程序員 C
既想使用 A
的 Util
,又想使用 B
的 Util
,這個時候可以分別將 A
、B
兩個人的 Util
類放入兩個不同的包下,就可以解決命名沖突了。
對于控制訪問,我們將在本小節(jié)的包作用域部分舉例講解。
2. 包聲明
2.1 語法
在一個類中,使用關(guān)鍵字 package
在類的頂部聲明一個包:
package service;
public class DemoService {
...
}
上面的代碼就表示 DemoService
類放到了 service
包下,我們也可以說:DemoService
在 service
包中聲明。我們的類如果在包中聲明,那么類就必須放置在源碼目錄下以包名稱命名的子目錄中。這樣編譯器才能在系統(tǒng)中找到 Java
文件。
2.2 實例
下面我們使用 IntelliJ IDEA
來演示一個簡單的建包到建類的過程。
新建一個名為 imooc
的工程,之前我們已經(jīng)學(xué)過如何在 IDE 中新建工程,因此這里不再截圖演示。查看下圖,imooc
是工程名,src
是源碼目錄。

首先在源碼目錄新建一個包,命名為 service
。在 src
目錄上點擊鼠標(biāo)右鍵 -> New -> Package

填入包名 service

輸入 Enter
完成包的新建,此時工程結(jié)構(gòu)如下:

接下來在包下面新建一個 DemoService
類。在 service
點擊右鍵 -> New -> Java Class,輸入類名稱 DemoService
完成新建,此時工程結(jié)構(gòu)如下:

而 IDE 也會在類的頂部自動為我們聲明包:

這樣就完成了一個包到類的新建。
重復(fù)以上步驟,我們接著在源碼目錄下新建一個 util
包,在 util
包中新建一個 DemoUtil
類。
此時,imooc
工程在物理硬盤上的文件結(jié)構(gòu)為:
├── imooc
│ └── src
│ ├── service
│ │ └── DemoService.java
│ └── util
│ └── DemoUtil.java
通過上述一系列演示,我們驗證了這個結(jié)論:所有的 Java 文件對應(yīng)的目錄層級要和包的層級保持一致。
另外,包下面也可以包含子包,子包中也可以聲明類,例如,可以在上面的 service
包下新建一個 demo
包,在 demo
包下新建一個 DemoClass
類。如下代碼可以看到類頂部包的聲明,要使用.
分隔多個包名:
package service.demo;
public class DemoClass {
}
3. 導(dǎo)入包
3.1 完整類名導(dǎo)入
在類名前面加上包名(我們稱為完整類名),就可以使用指定包中的類。例如,對與上面示例的項目結(jié)構(gòu),我們想在 DemoService
類中使用 DemoUtil
類,可以這樣寫:
package service;
public class DemoService {
util.DemoUtil demoUtil = new util.DemoUtil();
}
如果使用同一包中的類,則不必在類前面指定包名。
3.2 import 關(guān)鍵字導(dǎo)入
上面的語法比較冗長,我們可以使用 import
關(guān)鍵字在文件頂部導(dǎo)入指定包中類,在代碼中就不必指定包名來使用類了。例如,上面的代碼可以改成寫:
package service;
import util.DemoUtil;
public class DemoService {
DemoUtil demoUtil = new DemoUtil();
}
Tips:如果有兩個或多個類名相同,那么就不能使用
import
關(guān)鍵字同時導(dǎo)入了,此時建議使用完整類名的方式使用類。當(dāng)然,實際的編碼中,我們也不推薦命名多個同名類。
3.3 通配符導(dǎo)入
在使用 import
關(guān)鍵字時,可以使用通配符 *
來導(dǎo)入指定包下面的所有類。例如:
package service;
import util.*;
public class DemoService {
DemoUtil demoUtil = new DemoUtil();
}
盡管它看起來非常方便,但是我們不推薦這種寫法。一方面降低了代碼的可讀性,另外也可能導(dǎo)致一些問題。
還有一點需要特別提醒,java.lang
包中的所有類會都被編譯器隱式導(dǎo)入,所以在使用諸如 System
、String
等類的時候,我們不需要手動導(dǎo)入。
4. 包作用域
所謂包作用域,就是沒有使用訪問修飾符修飾的字段和方法。同一個包中的類,可以訪問包作用域的字段和方法。
例如,在 com.imooc
包下面有一個 Student
類:
package com.imooc;
public class Student {
// 包作用域的屬性
String name;
// 包作用域的方法
void sayHello() {
System.out.println("你好!" + name);
}
}
在 com.imooc
包下面的 Test
類,訪問 Student
類中的字段和方法:
package com.imooc;
public class Test {
public static void main(String[] args) {
Student student = new Student();
// 操作包作用域下屬性
student.name = "Colorful";
// 訪問包作用域下的方法
student.sayHello();
}
}
由于 Student
與 Test
都屬于 com.imooc
包,所以可以訪問包作用域內(nèi)的字段和方法。
5. 包命名規(guī)范
包名應(yīng)該使用全小寫字母命名,這樣易于將包名與類名區(qū)分開。
為了避免名稱沖突,通常建議以公司域名的倒置來確保唯一性。例如,慕課網(wǎng)域名為 imooc.com
,項目的包命就應(yīng)該為 com.imooc
,其具體的子包可根據(jù)功能業(yè)務(wù)命名。
再舉幾個例子,大名鼎鼎的 Apache 軟件基金會的包命名為 org.apache
,Java 領(lǐng)域最知名開源框架 Spring
包名為 org.springframework
。
6. 小結(jié)
本小節(jié)我們學(xué)習(xí)了 Java 包的定義與使用,Java 提供包的機制主要是為了類避免命名沖突。我們也知道了如何聲明包、如何導(dǎo)入包以及包作用域的概念,實際項目的包名推薦使用域名倒置。
包的使用,除了在我們自己編寫的項目中非常常見,你也可以翻閱 JDK 的源碼,Java 平臺按照功能將類放入了不同的包中。例如:基礎(chǔ)的類在 java.lang
包中,用于讀寫的類在 java.io
包中,一些工具類放在 java.util
包中。Java 平臺由成百上千的類組成,把這些類放入包中,可以使程序結(jié)構(gòu)井井有條。