上幾篇文章我們討論了類蒿讥、成員變量、成員方法抛腕、構(gòu)造方法芋绸,對(duì)于成員變量來說,它還分為實(shí)例變量和靜態(tài)變量担敌,成員方法也分普通方法和靜態(tài)方法摔敛。聲明方法的格式里有個(gè)東西叫“訪問修飾符”,當(dāng)時(shí)沒細(xì)講全封,這篇我們就詳細(xì)聊聊它马昙。
之前我們寫的程序都有這么一個(gè)特點(diǎn):變量前什么都不寫,方法前寫個(gè)public刹悴。那這個(gè)public是什么意思呢行楞?從字面上理解,public英文是“公有的”土匀,是一種訪問修飾符子房。其實(shí)在java里,訪問修飾符除了公有public, 還有另外三類恒削,分別是受保護(hù)池颈,英文protected; 默認(rèn),不寫任何修飾符就代表默認(rèn); 以及私有钓丰,英文private躯砰。怎么理解這些東西呢?大家都知道携丁,每個(gè)國(guó)家都有機(jī)密文件琢歇,這些機(jī)密文件被妥善的保護(hù)兰怠,看這些文件的人同樣得是身份很特別的人,甭說外國(guó)人了李茫,本國(guó)人都不能隨意瀏覽揭保。而且文件上會(huì)貼有類似“絕密”“無保密”“內(nèi)部”等標(biāo)簽。訪問修飾符就可以想象成這種給予文件權(quán)限的標(biāo)簽:
下面我就帶著大家一個(gè)一個(gè)總結(jié)它們的特點(diǎn)魄宏。先說public秸侣。創(chuàng)建一個(gè)叫Test.java的文件,然后復(fù)制粘貼以下代碼:
假設(shè)我現(xiàn)在有一個(gè)國(guó)家機(jī)密文件宠互,里面寫著國(guó)家目標(biāo)和國(guó)家計(jì)劃味榛。我創(chuàng)建了一個(gè)叫Test的類代表該文件,目標(biāo)用變量countryGoal表示予跌,計(jì)劃用countryPlan方法表示搏色。修飾符其實(shí)不光可以修飾方法,還可以修飾變量券册,甚至是類频轿。我現(xiàn)在只給變量和方法前面都加上了public,對(duì)類暫時(shí)用不著烁焙,因?yàn)橹挥袔讉€(gè)類不在同一文件里時(shí)類修飾符才有用航邢。然后我在main函數(shù)里聲明出了一個(gè)對(duì)象p1,雖然它只是Test的一個(gè)對(duì)象考阱,但為了便于理解大家可以把它暫時(shí)當(dāng)成一個(gè)人翠忠。p1嘗試訪問國(guó)家目標(biāo)和國(guó)家計(jì)劃鞠苟,看他/她是否能成功:
最后一行原來是“100年內(nèi)我大天朝牛b哄哄”改成了“100年內(nèi)我大中華四夷賓服”乞榨,因?yàn)橛X得把b這個(gè)字形容自己的祖國(guó)再怎么樣聽起來也不雅,后面的截圖我懶得改了当娱,大家知道就行了吃既。沒問題,這個(gè)人既可以訪問countryGoal跨细,又可以訪問countryPlan鹦倚。所以,我們第一個(gè)結(jié)論就是:當(dāng)成員變量或成員方法是public的時(shí)候冀惭,對(duì)象又和它們?cè)谕愔姓鹦穑强梢噪S意被訪問的。就好像是權(quán)限很低的文件散休,可以隨便看媒楼。那不同類中呢?
我把代表文件的那部分代碼挪到了Document類中戚丸,在Test里聲明出了一個(gè)Document對(duì)象p1划址。這次p1再次嘗試訪問國(guó)家目標(biāo)和國(guó)家計(jì)劃,看是否能成功:
沒問題,p1還可以訪問夺颤。如果這兩個(gè)類在不同文件里呢痢缎?之前我們?cè)陬悺⒊蓡T變量世澜、成員方法(3)那篇里曾演示過多個(gè)類在不同文件中的執(zhí)行独旷,我也說過好多時(shí)候其實(shí)都是一個(gè)類一個(gè)文件,只不過為了方便演示寥裂,咱們都放到了一起势告,僅僅如此。現(xiàn)在咱們就演示一下抚恒,如果放在不同的文件中咱台,pulic修飾符會(huì)有什么效果。演示之前升級(jí)一下我們的開發(fā)工具俭驮。由于我們的例子比較簡(jiǎn)單回溺,只需要兩個(gè)文件就夠了,一個(gè)放Document類混萝,另一個(gè)放Test類遗遵。可如果這個(gè)項(xiàng)目很大呢逸嘀?開發(fā)目錄下是不是會(huì)產(chǎn)生好多個(gè).java文件车要?用記事本就不好管理了。所以從現(xiàn)在開始崭倘,我們不再用記事本了翼岁,開始用咱們第一篇最后說到的那個(gè)工具-Eclipse。有時(shí)候我們聽別人說IDE這個(gè)詞司光,IDE就是integrated development environment琅坡,翻譯過來就是集成開發(fā)工具。Eclipse既幫助我們寫代碼残家,也幫助我們維護(hù)代碼榆俺,功能很強(qiáng)大。而且這個(gè)工具是開源的坞淮,咱們可以直接下載使用茴晋。當(dāng)然,市面上還有別的類似軟件回窘,大家可以自行下載試試诺擅。
去官網(wǎng)下載最新版eclipse,安裝過程比較簡(jiǎn)單毫玖,我就不細(xì)說了掀虎。雙擊執(zhí)行文件打開凌盯,一開始需要你填workspace,也就是工作區(qū)烹玉,意思就是你以后要把項(xiàng)目存到哪個(gè)文件夾下驰怎。如果一個(gè)工作區(qū)里還沒有任何項(xiàng)目,它會(huì)提示個(gè)Eclipse的歡迎界面二打,叉掉之后就是你的工作臺(tái):
默認(rèn)情況下左邊是你的項(xiàng)目列表县忌,右邊是代碼區(qū),下面是運(yùn)行結(jié)果继效。當(dāng)然症杏,你如果不喜歡這種布局可以修改。現(xiàn)在我們先新建個(gè)項(xiàng)目試試瑞信。因?yàn)槲沂怯⑽陌胬鞑桶从⑽陌娴闹噶钭撸狐c(diǎn)擊左上角File -> New -> Project打開項(xiàng)目對(duì)話框,選擇Java Project后點(diǎn)擊下一步:
項(xiàng)目名稱就輸入Documents吧凡简,國(guó)家密檔嘛逼友。
然后一直下一步到最后,項(xiàng)目就建完了秤涩,在這個(gè)過程中你能看到Eclipse會(huì)把jdk和jre加進(jìn)去帜乞。新建的項(xiàng)目比較空,只有src文件夾和jre library筐眷。
現(xiàn)在把Test和Document這兩個(gè)類加進(jìn)去弓叛,每個(gè)類單獨(dú)占一個(gè)文件题暖,所以我們要新建兩個(gè).java文件蛉艾。右鍵點(diǎn)擊src -> new ->class打開類對(duì)話框科贬,類名是Document:
看見上圖名稱下面還有個(gè)修飾符那一欄嗎?默認(rèn)它是public的振定,點(diǎn)擊確定會(huì)創(chuàng)建一個(gè)叫Document.java的文件必怜,并且類名為Document,修飾符是public:
剛才說了后频,如果幾個(gè)類都在同一個(gè)文件里那沒必要用類修飾符。但現(xiàn)在Document和Test不在同一個(gè)文件里了暖途,那么它也要受到修飾符的控制卑惜。同樣步驟創(chuàng)建Test.java,不過勾選上main函數(shù)驻售,代表它是主類:
現(xiàn)在的項(xiàng)目是這個(gè)樣子:
我們發(fā)現(xiàn)在項(xiàng)目和java文件中間多了一層露久,上面寫著(default package)這一層是什么呢?我并沒有建這么個(gè)東西呀欺栗?這就引來了我們這篇文章的第二個(gè)概念–包毫痕,英文叫package征峦。在實(shí)際的自動(dòng)化測(cè)試項(xiàng)目里,有些文件是為了儲(chǔ)存網(wǎng)頁上的控件消请,有些文件是為了處理邏輯需求栏笆,有些文件是為了連接數(shù)據(jù)庫,功能各不相同臊泰,所以即便你把各種類區(qū)分開寫了很多文件蛉加,那也得需要根據(jù)不同的職責(zé)來管理這些文件。咱們的操作系統(tǒng)里都用文件夾來管理文件缸逃,而包就相當(dāng)于java里的文件夾针饥。所以,java使用包的概念來管理類需频、文件丁眼、模塊或功能。之前說java其中一個(gè)重要部分叫做類庫昭殉,本質(zhì)上就是包的一種應(yīng)用户盯。
如果在創(chuàng)建文件前沒創(chuàng)建包,eclipse會(huì)自動(dòng)補(bǔ)上一個(gè)默認(rèn)的包饲化,名字就叫default莽鸭。包也有自己的命名規(guī)則,一般是按照“所在公司的互聯(lián)網(wǎng)域名.公司名.項(xiàng)目名.模塊名”這種格式吃靠,每個(gè)字段首字母為小寫硫眨,字段之間用點(diǎn)隔開。比如我要為阿里巴巴的淘寶做項(xiàng)目巢块,我可以把負(fù)責(zé)測(cè)試的模塊寫到一個(gè)包里礁阁,包名就是com.alibaba.taobao.tests。
和類名首字母大寫或是變量方法首字母小寫一樣族奢,包的命名規(guī)則也是個(gè)約定俗成的東西姥闭,你說我偏不遵守,也沒什么越走,只不過顯得有點(diǎn)不專業(yè)棚品,但程序執(zhí)行上沒問題。關(guān)于包還有些東西要說廊敌,下篇文章我會(huì)用字符串舉例說說類庫铜跑,到時(shí)大家更能體會(huì)到包的作用。
來骡澈,咱們把包名改一下锅纺,我也不想寫得特別復(fù)雜,就用com.test吧肋殴,意思到了就行囤锉,最后做項(xiàng)目實(shí)戰(zhàn)時(shí)我會(huì)寫得規(guī)范點(diǎn)坦弟。右鍵點(diǎn)擊src -> New -> Package打開包對(duì)話框,輸入com.test官地,點(diǎn)擊確定酿傍。
之后我們會(huì)發(fā)現(xiàn)com.test并沒有把(default package)取代,沒關(guān)系区丑,手動(dòng)把Document.java和Test.java拖拽進(jìn)去拧粪。拖完會(huì)驚奇地發(fā)現(xiàn)(default package)不見了:
現(xiàn)在把剛才用記事本寫的程序復(fù)制粘貼進(jìn)去:
這兩個(gè)文件都在com.tests包下,現(xiàn)在右鍵點(diǎn)擊Test.java -> Run As -> Java Application執(zhí)行程序沧侥,注意一定要在主類上執(zhí)行可霎,否則找不到main函數(shù):
運(yùn)行結(jié)果顯示正確,沒有報(bào)錯(cuò)宴杀,證明同包下public修飾的變量和方法也可以被訪問癣朗。那現(xiàn)在就能得出一個(gè)結(jié)論了:不管在同類還是同包不同類,public修飾的變量和方法都是可以被訪問的旺罢。
第二個(gè)說protected】跤啵現(xiàn)在把Document.java里的countryGoal變量和countryPlan方法都改成protected,Test.java不變扁达,然后運(yùn)行程序正卧,發(fā)現(xiàn)還是通過的:
既然在不同文件都可以通過,那相同文件相同類肯定也沒問題跪解。所以我又得出一個(gè)結(jié)論:不管在同類炉旷,還是同包不同類,protected修飾的變量和方法也都是可以被訪問的叉讥。暫時(shí)還沒看出來public和protected的區(qū)別窘行,不過別著急,咱們繼續(xù)看图仓。
Protected試完咱們?cè)囋嚹J(rèn)的罐盔。把Document.java里的protected移走,什么都不加救崔,就是默認(rèn)的惶看。Test.java保持原樣。運(yùn)行帚豪,還是通過:
這結(jié)論不用我說也知道吧碳竟?不管在同類,還是同包不同類狸臣,默認(rèn)修飾的變量和方法也都是可以被訪問的。有人開始不耐煩了昌执,你tm這是在逗我吧烛亦?息怒诈泼,一會(huì)兒就不同了。
最后用private:
看到了么煤禽?Test.java已經(jīng)提示錯(cuò)誤了: countryPlan方法和countryGoal變量都是invisible铐达。什么意思?主函數(shù)看不到它們檬果!用對(duì)象調(diào)用的時(shí)候雙雙不可訪問瓮孙,這就是private私有的意思,屏蔽了选脊,修飾符終于開始發(fā)威了杭抠。順便說一句,即使報(bào)錯(cuò)也是Eclipse勝過記事本的地方恳啥。記事本不會(huì)有什么紅波浪線提示代碼有誤偏灿,所以一段復(fù)雜的程序出了問題用記事本有時(shí)很難排錯(cuò)。
這是同包不同類的情況钝的。那我回退一步翁垂,試試同類。咱不嫌麻煩硝桩,我?guī)е蠹乙粋€(gè)一個(gè)地驗(yàn)證沿猜,通過程序的變化大家體驗(yàn)不同修飾符的區(qū)別。把Document.java文件里內(nèi)容再挪到Test.java里碗脊,現(xiàn)在Test.java就是這個(gè)樣子:
這回不報(bào)錯(cuò)了啼肩,而且執(zhí)行通過⊥。看來如果在同類中疟游,這個(gè)private也沒什么威力了。那咱們第四個(gè)結(jié)論就出來了痕支,用private的時(shí)候颁虐,同類可訪問,同包但不同類的情況下不能訪問卧须。
剛才演示的都是同類或同包不同類另绩,那如果不同包呢?不同包時(shí)public, private, protected和默認(rèn)會(huì)怎樣處理呢花嘶?還是從public開始笋籽。我們?cè)賱?chuàng)建一個(gè)包叫com.document,然后把Document.java拖拽進(jìn)去椭员。此時(shí)兩個(gè)文件的內(nèi)容修改成下面的樣子:
主類Test.java: 創(chuàng)建Document對(duì)象用來訪問變量和方法
第二個(gè)類Document.java: 聲明變量和方法用于被訪問
這時(shí)Eclipse又提示Test.java出錯(cuò)了车海,問咱們是不是需要import document:
Import的意思是導(dǎo)入,這里面是導(dǎo)入另一個(gè)包的信息隘击。為什么需要導(dǎo)入呢侍芝?這就是這篇文章的第三個(gè)概念:如果java程序分散在不同包中研铆,一個(gè)包中的類想要訪問另一個(gè)包中類的內(nèi)容則必須導(dǎo)入。導(dǎo)入其實(shí)就是把別的包的程序?qū)У轿疫@里來州叠,導(dǎo)進(jìn)來了不就相當(dāng)于在同一個(gè)包里了嘛棵红。選擇導(dǎo)入,這時(shí)會(huì)在Test.java文件頭部多加了import com.document.Document這么一行咧栗,同時(shí)錯(cuò)誤信息也不見了逆甜,表明導(dǎo)入成功。現(xiàn)在再運(yùn)行一下致板,看看public修飾符還允許不允許通過交煞。告訴大家吧,還是通過可岂,public等級(jí)非常低错敢。所以對(duì)于public來說,同類缕粹,同包不同類稚茅,不同包,都可以訪問平斩。其實(shí)這也是public本身的涵義亚享。公有嘛,誰都可以訪問绘面。
現(xiàn)在把public改成protected欺税。我們發(fā)現(xiàn)這次不行了,即便包都倒進(jìn)去了還是提示不可見揭璃。試試默認(rèn)呢晚凿?也不行,封得死死的瘦馍。我們感覺訪問修飾符在不同包的情況下威力非常大歼秽,各種不可見:
至于private,其實(shí)壓根不用試情组,肯定不行燥筷,同包不同類都不行,不同包肯定更不行了院崇。所以肆氓,再把不同包的情況包括進(jìn)去,咱們的結(jié)論就變成這張表:
變量和方法都遵循這個(gè)表上的規(guī)則底瓣,那類本身呢谢揪?也遵守,大家可以課后去實(shí)踐一下。這個(gè)結(jié)論不用死記键耕,忘了的話就用我這個(gè)方法驗(yàn)證一下就行了寺滚。
剛才的所有例子中countryGoal和countryPlan都是同時(shí)擁有相同的修飾符的柑营,要么都是public屈雄,要么都是private。如果我讓它們不一樣呢官套?比如變量countryGoal是private的酒奶,countryPlan方法是public的。很明顯前者在不同包情況下不可見奶赔,后者各種可見惋嚎。如果我非要在不同包的情況下訪問變量countryGoal呢?有沒有辦法站刑?現(xiàn)在我把這兩個(gè)文件寫成下面這樣:
我把countryPlan方法里面加了個(gè)字符串返回值另伍,而且返回的正是countryGoal變量。現(xiàn)在執(zhí)行程序绞旅,我們驚奇地發(fā)現(xiàn)用private修飾的countryGoal的結(jié)果被打印出來了摆尝,它竟然可以被訪問:
等等,仔細(xì)再看看程序因悲,countryGoal現(xiàn)在是在哪兒被訪問的堕汞?是不是countryPlan方法里邊?這么做意味著它不再被Test.java中的Document對(duì)象直接訪問了晃琳,而是間接通過countryPlan方法讯检。countryPlan方法和countryGoal變量在同一個(gè)類中,因?yàn)橥愔衟rivate是可見的卫旱,所以程序沒問題人灼。“方法公有但變量私有顾翼,然后通過方法訪問變量”這種做法非常普遍投放,咱們一定要記住。不過現(xiàn)在記不住也沒關(guān)系暴构,到時(shí)候我教大家寫項(xiàng)目的時(shí)候會(huì)經(jīng)常用這種寫法跪呈。所以,對(duì)于訪問修飾符取逾,我們一定要看這個(gè)變量或是方法到底在哪兒被訪問的耗绿,是同類?還是同包砾隅?還是不同包误阻?
那有人說你講這個(gè)訪問修飾符是干什么的?有什么意義?這就引出了我們這篇文章最后一個(gè)知識(shí)點(diǎn) – 封裝究反。前幾篇我說得最多的詞就是類寻定,對(duì)象,還是對(duì)象精耐。不管用王思聰咪蒙舉例也好狼速,還是自動(dòng)化的信息配置也好,它們都是對(duì)象卦停,對(duì)不對(duì)向胡?所以,java是一種面向?qū)ο蟮恼Z言惊完,一切都是圍繞對(duì)象展開僵芹。以前我學(xué)java的時(shí)候老師剛講類就直接把面向?qū)ο筮@個(gè)概念拋出來,又加上是英文授課小槐,一開始一頭霧水拇派,后來因?yàn)槔蠋煯吘顾礁撸也怕愣涮K晕抑v的時(shí)候就先帶大家寫幾個(gè)程序件豌,由淺入深慢慢理解對(duì)象這個(gè)概念,這時(shí)再拋出面向?qū)ο蟠蠹依斫馄饋砭蛻?yīng)該容易多了拄显。我不知道你們學(xué)沒學(xué)過別的語言苟径,尤其是C語言,它被稱為面向過程語言躬审,沒有類和對(duì)象這個(gè)概念的棘街,沒有java方便,這里咱們就不討論了承边。
面向?qū)ο笳Z言有三大特征遭殉,而封裝就是第一個(gè)特征。你看博助,這幾種訪問修飾符险污,是不是感覺像塑料袋一樣把里面的內(nèi)容封住,或是像墻一樣把訪問者拒之門外富岳?拒之門外的目的就是為了保證代碼的安全性蛔糯,因?yàn)樽鲰?xiàng)目的時(shí)候不是所有人都可以對(duì)一些特定文件里的類,方法窖式,或是變量隨意進(jìn)行訪問蚁飒。封裝就是通過不同的訪問修飾符來控制類,變量萝喘,方法的可見性淮逻,以達(dá)到保護(hù)代碼的目的琼懊。
這篇文章的源代碼是有10個(gè)小項(xiàng)目,分別在DocumentsForDefaultDiffPkgs爬早,DocumentsForDefaultSamePkgDiffClasses哼丈,DocumentsForPrivateSameClass,DocumentsForPrivateSamePkgDiffClasses筛严,DocumentsForPrivateValPublicMeth醉旦,DocumentsForProtectedDiffPkgs,DocumentsForProtectedSamePkgDiffClasses脑漫,DocumentsForPublicDiffPkgs,DocumentsForPublicSameClass髓抑,DocumentsForPublicSamePkgDiffClasses)
本篇知識(shí)點(diǎn)及注意事項(xiàng):
1. 訪問修飾符結(jié)論: 1)不管在同類、同包不同類优幸、不同包,public修飾的變量和方法都是可以被訪問的褪猛;2)protected和default只可以在同類以及同包不同類之間訪問网杆,兩者區(qū)別講繼承時(shí)說;3)private只可以在同類間訪問伊滋。
2. java使用包的概念來管理類碳却、文件、模塊或功能笑旺。
3. 如果java程序分散在不同包中昼浦,一個(gè)包中的類想要訪問另一個(gè)包中類的內(nèi)容則必須導(dǎo)入,關(guān)鍵字是import筒主。
4. “方法公有但變量私有关噪,然后通過方法訪問變量”這種做法非常普遍,對(duì)于訪問修飾符乌妙,我們一定要看這個(gè)變量或是方法到底在哪兒被訪問的使兔,是同類?還是同包藤韵?還是不同包虐沥?