詳細(xì)聊一聊Java中的包機(jī)制
1. 定義
包(Package)類似于磁盤上的文件夾,通過包名可以找到對應(yīng)文件路徑,例如包test.demo.example對應(yīng)文件路徑為test/demo/example。
2. 核心作用
- 防止命名沖突
假如在包test.demo.example1和test.demo.example2這兩個包中都有一個Java類demo01,由于在不同包中相同類名不會引起沖突,所以可以在不同包中命名相同的Java類,但是無法在同一個包下創(chuàng)建另一個相同名字的類。 - 代碼組織和管理
將功能相似的類集中管理放在同一個包中,便于程序員管理,快速定位到功能模塊。 - 訪問控制
在同一個包中,不同類的設(shè)置了public訪問屬性的成員可以相互訪問彼此成員,無需導(dǎo)入對應(yīng)的包,但是外部包無法直接訪問,需要通過導(dǎo)包來調(diào)用其他包中的類的成員或方法。 - 支持模塊化開發(fā)
通過包劃分功能模塊,例如,要完成一個外賣系統(tǒng),用戶模塊在包test.demo.user中,訂單模塊在test.demo.order中,便于團(tuán)隊(duì)協(xié)作和管理,提升開發(fā)效率
3. 討論
- 為什么Java要引入包機(jī)制,而不復(fù)用C/C++的頭文件
解決命名沖突
Java的包機(jī)制可以在不同包中創(chuàng)建相同命名的類
package test.demo.example; public class Demo01 {//無修飾符 public String name1="test1"; public Demo01() {} public void getname() { System.out.print(name1); } } package test.demo.example1; public class Demo01{ public String name2="test2"; public Demo01() {} public void getname() { System.out.print(name2); } } package test.demo.example2; public class main { public static void main(String []args) { test.demo.example.Demo01 de01=new test.demo.example.Demo01(); de01.getname(); test.demo.example1.Demo01 de02=new test.demo.example1.Demo01(); de02.getname(); } }
但是在C++中,若兩個不同頭文件中命名了相同的類,引用這兩個頭文件后在編譯時由于重名沖突會報錯。
//test01.h #pragma once #include<iostream> void demo()//全局可見 { std::cout << "demo" << std::endl; } //test02.h #pragma once #include<iostream> void demo()//全局可見 { std::cout << "demo1" << std::endl; }
//main.cpp #include"test01.h"http://包含頭文件 #include"test02.h" int main() { demo();//調(diào)用全局函數(shù) return 0; }
編譯后出現(xiàn)如下錯誤:
函數(shù)“void demo(void)”已有主體 Project1 E:\C++\test\Project1\test02.h
簡化依賴管理
簡單來說,Java中包通過import自動解析類路徑,因?yàn)榘蛯?yīng)相應(yīng)文件目錄,編譯器自動根據(jù)包名查找類文件,無需手動指定路徑。而C++/C中需要手動包含收頭文件并處理重復(fù)包含,C++/C在引用其他目錄的頭文件時,需要顯示指定路徑,例如:
#include"include/my_header.h"
否則編譯器無法找到頭文件,但是我們在平常寫C++代碼的時候并沒有顯示指定頭文件路徑,原因有兩點(diǎn):
- 若頭文件與源文件在同一目錄,不需要手動添加路徑,編譯器默認(rèn)搜索當(dāng)前目錄
- IDE會自動配置路徑,程序員感知不到顯示操作
強(qiáng)化封裝性
Java中包級訪問權(quán)限(默認(rèn)權(quán)限修飾符)限制跨包訪問,即類、方法、屬性若未添加
public
/protected
/private
,僅允許同包內(nèi)訪問,外部包無法通過導(dǎo)入或全限定名繞過權(quán)限限制,編譯器直接報錯。而C++頭文件定義的全局函數(shù)或變量默認(rèn)公開,容易被外部隨意訪問。用以下代碼解釋:
package test.demo.example; class Demo01 {//無修飾符 public String name1; public Demo01() {} public void test1() { System.out.print("demo01"); } } //同一個包下 package test.demo.example; public class Demo02 { private String name2; public static void main(String[]args) { Demo01 de01=new Demo01(); de01.test1(); } }
package test.demo.example1;//外部包 import test.demo.example.Demo01;//導(dǎo)入Demo01所在包 public class Demo1 { public static void main(String[]args) { Demo01 de01=new Demo01(); de01.test();//編譯無法通過 } }
編譯出現(xiàn)如圖所示錯誤:該錯誤顯示無法識別demo01類型
//test01.h #pragma once #include<iostream> // 未使用 static 或匿名命名空間,全局可見 void internalDebug() { std::cout << "內(nèi)部調(diào)試方法" << std::endl; } class test01 { public: // 默認(rèn)訪問權(quán)限為 public(若不顯式聲明 private) void debug() { std::cout << "內(nèi)部調(diào)試方法" << std::endl; } }; //main.cpp #include"test01.h"http://包含頭文件 int main() { internalDebug();//直接調(diào)用全局函數(shù)(可能意外暴露) test01 t1; t1.debug();//直接訪問類成員 return 0; }
- 頭文件中的
internalDebug()
函數(shù)默認(rèn)全局可見,任何包含該頭文件的代碼均可調(diào)用,可能導(dǎo)致命名沖突或誤用。 - C++ 類成員默認(rèn)訪問權(quán)限為
private
,但此處顯式聲明為public
,以模擬常見開發(fā)習(xí)慣 - 即使將
test01.h
視為“內(nèi)部工具”,其他源文件仍可通過包含頭文件直接調(diào)用其內(nèi)容,缺乏模塊隔離
面向?qū)ο笤O(shè)計(jì)深度整合
Java中包與類加載器結(jié)合,強(qiáng)制代碼模塊化,Java中的變量,方法都在類中實(shí)現(xiàn)和定義,而C++頭文件可能混合全局函數(shù),變量和類的定義
跨平臺與標(biāo)準(zhǔn)化
Java中包名使用
.
分隔符,與操作系統(tǒng)無關(guān);而C++頭文件路徑依賴操作系統(tǒng)分隔符(如\
或/
),Windows系統(tǒng)文件路徑用“\”分隔符,Linux系統(tǒng)文件路徑用“/”分隔符。
總結(jié)
到此這篇關(guān)于Java中包機(jī)制的文章就介紹到這了,更多相關(guān)Java包機(jī)制內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringBoot實(shí)現(xiàn)發(fā)送電子郵件
這篇文章主要介紹了SpringBoot實(shí)現(xiàn)發(fā)送電子郵件,電子郵件是—種用電子手段提供信息交換的通信方式,是互聯(lián)網(wǎng)應(yīng)用最廣的服務(wù)。通過網(wǎng)絡(luò)的電子郵件系統(tǒng),用戶可以非??焖俚姆绞?,與世界上任何一個角落的網(wǎng)絡(luò)用戶聯(lián)系,下面就來看看SpringBoot如何實(shí)現(xiàn)發(fā)送電子郵件吧2022-01-01Java中valueOf和parseInt的區(qū)別詳解
這篇文章主要介紹了Java中valueOf和parseInt的區(qū)別詳解,在編程中,遇到類型轉(zhuǎn)換,好像會經(jīng)常用到 parseInt 和 valueOf,當(dāng)然這里只拿 Integer 類型進(jìn)行陳述,其他類型也是雷同的,需要的朋友可以參考下2024-01-01簡單介紹區(qū)分applet和application的方法
applet和application都是Java語言編寫出來的應(yīng)用程序,本文簡單介紹了二者的不同之處,需要的朋友可以參考下2017-09-09ActiveMQ基于zookeeper的主從(levelDB Master/Slave)搭建
這篇文章主要介紹了ActiveMQ基于zookeeper的主從levelDB Master/Slave搭建,以及Spring-boot下的使用方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-08-08Spring Boot 2 Thymeleaf服務(wù)器端表單驗(yàn)證實(shí)現(xiàn)詳解
這篇文章主要介紹了Spring Boot 2 Thymeleaf服務(wù)器端表單驗(yàn)證實(shí)現(xiàn)詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2019-11-11spring boot啟動出現(xiàn)Unable to start ServletWe
在使用SpringBoot時,啟動報錯可能源于多種原因,錯誤提示為缺少ServletWebServerFactory bean,初步分析可能是缺少spring-boot-starter-web依賴或@EnableAutoConfiguration注解,感興趣的可以了解一下2024-10-10