java第七章学习笔记:访问控制---java世界的卫兵
【因為每一章都篇幅比較長(10多頁,難免有的地方會寫錯字,如發(fā)現(xiàn)請指正,本人不勝感激)】
【今天看到我居然有一名粉絲,內(nèi)心還是有點小激動的,之間我是一枚不是很喜歡技術(shù)的妹紙,但是從現(xiàn)在開始,我從被動學習開始轉(zhuǎn)為主動學習,因為我想給自己一個機會,也許它就會還我一個驚喜呢。好了廢話不多說了,如果有像我一樣不喜歡技術(shù)的妹紙希望我能給你鼓勵。↖(^ω^)↗】
【ps:因為時間有點緊,所以排版不好,后期我會調(diào)整一下】
上一章介紹了類與對象的基本用法,本章介紹如何控制類及其成員的訪問權(quán)限,包括:包的使用、類的訪問控制、成員的訪問控制以及final的變量以及static關(guān)鍵字
7.1 包的使用
在實際開發(fā)中,往往需要開發(fā)很多不同的類,能否方便高效的組織這些類對項目的開發(fā)和使用具有和重要的意義。
提示:標準的java類庫分布在多個包中,eg:java.lang,java.util等
使用包的目的:可以在同一個項目中使用相同名稱的類,本節(jié)從類的放置與導(dǎo)入兩個方面對包及使用進行介紹。包括:
7.1.1 聲明創(chuàng)建包
要想將類放在指定的包中,就必須使用package語句,語法如下:
package<包名>;
- package語句必須放在源文件的最前面(有效代碼第一行)
- 每個源文件最多一句package,因為一個類不能屬于兩個包
- 包名用點“.”分隔,eg:java.lang,這就表示此源文件中的類在java包下的lang子包中。
- 在實際開發(fā)中,包可能分很多級,越復(fù)雜的系統(tǒng),包越多,級也可能越多;eg:
編譯上面的代碼,并將編譯后的.class文件拷貝到相應(yīng)的包(lixiaoxi.bupt)對應(yīng)的文件夾中,即Test.class文件放到所在目錄下的lixiaoxi文件中的bupt文件下,文件放置完后,其目錄結(jié)構(gòu)為:
從上圖可以看出,包實際上代表的是文件夾(目錄路徑)如果不將編譯后的class文件放在相應(yīng)的文件夾中,則無法運行。
提示 在實際開發(fā)中會為每一個類制定具體的包。
運行結(jié)果:
使用命令行運行在具體包中的類時要使用全稱類名,即:包名與類名順次用“.”隔開,eg(java lixiaoxi.bupt.Test),若只是(java Test)則會報“java.lang.NoClassDefFoundError”異常
提示:在運行程序時,要將當前目錄設(shè)置為最外層的包文件夾所在的目錄(即本例的lixiaoxi文件夾所在目錄,而不是類文件所在目錄,否則在有些情況下運行可能報錯)
- 在開發(fā)中要注意不要把類文件隨意拷貝到別的目錄中,開發(fā)中想改變類所在的包,一定要修改源代碼重新編譯,只是拷貝、移動類文件是不對的
- 如果沒有在源文件中使用package語句,那么這個源文件中的類就被放置在一個匿名包中,匿名包是一個有名字的包,其代碼編譯后的類文件與源文件在同一個目錄中即可
注意:后面例子中有包的,不要忘記將編譯后的class文件放到相應(yīng)的文件,否則程序不能正常執(zhí)行
7.1.2 引入包內(nèi)的資源
當一個類使用與自己處于同一個包中的類————-直接訪問;
使用其他包中的類———————import語句;語法如下:
import<包名>.*;//使用指定包中的所有類,但不包括子包中的類
import<包名>.類名;//使用指定包中特定類包名可以是一個由“.”分隔的序列,eg:”java.lang”、“java.util”
- import語句放在package語句之后,類聲明之前
import語句只是在編譯的時候有作用,另外java.lang包中的類系統(tǒng)是自動引入的,相當于在每個源文件中系統(tǒng)在編譯時會自動加上“import.java.lang.*語句”
-.”*”可以導(dǎo)入第一層的所有類,但是若要使用多個包中的同名類就不行;兩個包中有同名類,但只用到其中一個及其他不同名的類。
- 兩個包中有同名類,且都要使用
1、兩個包中有同名類,但只用到其中一個及其他不同名的類
eg:java.util和java.sql包中都有名稱為Date的類,在程序中要同時使用這兩個包中的很多類,但只用到j(luò)ava.util包中的Date類:
運行結(jié)果:
The type Date is ambiguous(引起歧義)
系統(tǒng)報Date類匹配失敗,因為在源代碼中用import語句引入兩個包中的所有類,兩包都有Date類,系統(tǒng)不知道應(yīng)該匹配哪一個,如果只用到j(luò)ava.util包中的Date類,可以將import util中修改為:
import java.util.*; import java.util.Date; import java.sql.*;這樣就不會報錯了,因為系統(tǒng)會優(yōu)先匹配import語句中明確給出類名的類;
這就是為什么 會在別人的方法中看到已經(jīng)有了.*還要指定類名。
2、兩個包中有同名類,且都要使用
使用兩個不同包中的同名類只靠import就無法解決了,eg:將上面demo改為:
系統(tǒng)報具體指定名稱的同類名只能引入一次的錯誤,真正的解決辦法是在使用同名類的地方使用全稱類名eg:
package lixiaoxi.bupt; import java.util.*; import java.sql.*;public class Test {public static void main(String[] args){java.util.Date date=new java.util.Date();//使用java.util中的Date類java.sql.Date d1=new java.sql.Date(123);//使用java.sql中的Date類,數(shù)字的含義不必理會//其他使用別的類的代碼省略} }需要特別注意:不要使用星號(*)代替包,eg:下面的導(dǎo)入語句是非法的。
import java..;
7.1.3 靜態(tài)引入
導(dǎo)入語句不但可以導(dǎo)入類,還具有導(dǎo)入靜態(tài)方法和靜態(tài)成員變量的功能,不過要在關(guān)鍵字“import”和包名之間添加關(guān)鍵字“static”,具體語法如下:
import static <包名>.<類名>.;
import static <包名>.<類名>.<具體方法/成員變量名>;
上面打印就不需要像以前一樣列出方法所在的類的類名了;
運行結(jié)果:
實際上,沒有很多開發(fā)人員使用靜態(tài)引入,因為這種代碼編寫形式容易降低代碼的可讀性,造成維護困難。但是以下兩個特別的地方有很實際的作用,可以簡化開發(fā)。
- 如果對Math類使用靜態(tài)引入,就可以采用更加自然的方式在表達式中使用算數(shù)函數(shù),eg:”pow(3,2)+sqrt(4)”比“Math.pow(3,2)+Math.sqrt(4)”看起來更清晰
- 如果需要使用大量的帶有繁瑣的名字的靜態(tài)常量,使用靜態(tài)引入代碼會清晰明了,eg:”MONAY”比“Calendar.MONDAY”看起來簡單很多
7.2 類的訪問控制 (public或默認不寫)
首先了解類訪問的含義:若一個類(類A)訪問另一個類(類B)時,其指類A具有以下三種操作:類訪問實際上是指:一個類對另一個類的可見性,eg:類A看不見類B,則類B中的方法和變量的訪問權(quán)限對A來說就為不可訪問,類的訪問權(quán)限有兩種:
公有級別訪問(public類型)
默認訪問級別(什么都不寫)
因此,聲明每個類時無論是否明確指定,其都將有一個訪問控制級別;
7.2.1 公有訪問級別
帶有“public”修飾的類,任何包中的任何類都可以訪問此訪問級別的類。需注意:盡管從訪問級別上其可以被任何包中的任何類訪問,但是編寫代碼時,如果訪問其他類與其不再同一個包,依然需要引入語句或全稱類名
運行結(jié)果:
提示:javac命令一次可以編譯多個源文件,只要把編譯的多個源文件用空格符分開,逐一列出即可;
7.2.2 默認訪問級別
可以將默認訪問級別看做包訪問,因為默認訪問級別下的類只能被同一個包中的類看到,包外不可見
將類Test2的public去掉就看到兩處錯誤:分別是聲明引用于創(chuàng)建對象時都無法都無法訪問類Test2,因為Test2具有默認訪問級別,并與要訪問類位于不同包中,可以把兩個類放在同一個包中,或者將Test2設(shè)置為publlic的。
7.2.3 類與源代碼文件的搭配
一個源代碼文件中可以同時有多個類,類與源代碼文件搭配的規(guī)則:
運行結(jié)果:
在實際開發(fā)中建議一個源代碼文件一個類,并且不管此類是不是public的,文件名與該類名相同,因為在實際開發(fā)中,可能會有成千上萬個類,若需要修改某一個類,那么該類的源代碼文件會很容易找到
7.3 成員的訪問控制(public,默認不寫,protected,private,)
成員包括(方法和成員變量【java中的成員除方法和變量外還有語句塊,內(nèi)部類】)
成員訪問指的是什么?指以下兩種不同的操作:
注意:成員的訪問權(quán)限基于類的訪問權(quán)限,即若類A有權(quán)訪問類B時,類B中成員的訪問權(quán)限對類A才起作用(即類A能調(diào)類B,才會考慮到成員變量訪問權(quán)限問題)
7.3.1 公共類型
用public:所有其他類,無論該類屬于哪個包,均能訪問該成員:eg:
運行結(jié)果:
對于繼承而言,規(guī)則為:如果父類的成員聲明為public,那么無論這兩個類是否在同一個包中該子類都能繼承其父類的該成員
7.3.2 私有類型(private)
不能被該成員所在類之外的任何類中代碼訪問eg:
雖然兩個類在同一個包中,方法show()卻不能被調(diào)用,因為被設(shè)置為private,自己類以外的任何代碼都是不可見的
7.3.3 默認類型(啥也不寫)
只對與此成員所屬類在同一個包中的類可見,對于同一個包中的類:默認類型相當于public,而對包外的類則相當于private
從繼承角度若父類的成員聲明為默認類型,則包內(nèi)的子類可以繼承而包外的則不可以
7.3.4 保護類型(protected)
其規(guī)則與默認類型一樣:對于同一個包中的類:默認類型相當于public,而對包外的類不是不能訪問而是只有通過繼承才能訪問該成員
成員訪問修飾符
提示:訪問修飾符不能用來修飾局部變量,否則將編譯報錯,而且局部變量作用域為局部,也沒有這個必要
7.3.5 java中封裝的實現(xiàn)
把東西包起來,換言之:成員變量和方法的定義都包裝于類定義之中,類定義可以看成是將構(gòu)成類的成員變量和方法封裝起來
通過限定類成員的可見性,可以使得類成員中的某些屬性和方法能夠不被程序的其他部分訪問,被隱藏起來,只能在所定義的類中使用,這就是面對對象中實現(xiàn)封裝的方式;
盡管技術(shù)上可以把成員變量標識為public,但是在實際中最好把所有的成員變量都保持為private,如果需要修改、設(shè)置或讀取該成員變量,應(yīng)該使用公共的訪問器方法,因此任何其他類中的代碼必須通過調(diào)用方法來訪問該成員變量,而不是直接使用;
這樣有助于提高程序的靈活性,便于做代碼修改和維護eg:
代碼中給size(身高)賦值為-5顯然是錯誤的,但由于size是public的,這就很難避免這種錯誤,解決辦法是為size變量編寫訪問器方法用private訪問限制修飾符保護size變量,修改后demo為:
public class Test {public static void main(String[] args){People test=new People();test.setSize(-5);//訪問成員變量size} } class People {private int size;//身高public void setSize(int newsize)//set成員變量的set方法{if(newsize>0){size=newsize;}else{System.out.println("身高必須大于0,請重新輸入");}}public int getSize()//size成員變量的get訪問器{return size;} }運行結(jié)果:
上面的demo對size成員變量做了封裝,必須通過訪問器方法設(shè)置size的值而在訪問器set方法中編寫了驗證之正確性的規(guī)則
提示:學會這種思想,對成員變量進行封裝,在訪問方法中編寫值正確性的驗證規(guī)則
eg 由于某種原因需要將size的類型修改為String,如果沒有使用封裝,那么所有用到size的地方都將不能使用,很可怕;而封裝以后,只需要對訪問器進行一定修改,可以使外面的調(diào)用者感覺不到變化,eg:
運行結(jié)果:
java封裝所需要遵循的規(guī)則:
關(guān)于訪問器方法,嚴格使用JavaBean命名規(guī)則set<成員變量>和get<成員變量>
7.4 final的變量
final能修飾很多類型的元素,而且功能含義各不相同;分幾部分介紹,本節(jié)介紹final變量
用final修飾的變量含義:該變量一旦被顯示初始化之后,其值就不能再被修改。要特別注意的是:對原始類型和引用類型的變量值不能修改的含義不完全一樣;
對于原始類型:一旦賦值以后,該值就不能修改;eg:final int x=10;則x的值永遠保持為10;
7.4.1 final的成員變量
一般情況下,不對成員變量賦初值,系統(tǒng)會給其默認初始值。但是對于final的成員變量,系統(tǒng)不會為其賦默認初始值,而是要求在構(gòu)造器完成之前必須顯式初始化,當然一旦初始化就不能修改。
提示:上面的成員變量指非靜態(tài)的成員變量 eg:
final變量初始化的時間只要在構(gòu)造器完成之前即可;其可選時機有如下三種:
- 聲明的同時進行初始化
- 在非靜態(tài)語句塊中進行初始化
- 在構(gòu)造器中進行初始化 eg:
運行結(jié)果為:
通過下面的demo來說明final引用的問題:
運行結(jié)果:
從上面的程序中可以看到,final引用所指向的對象的成員變量是可以修改的。當然要修改的成員變量本身不能為final的,在第九行和第十行之間插入stu=new Student()就會報錯:
因為stu是final的,其值(對象的地址)不能被修改即指向哪一個對象是不能修改的(eg:房東就是房子對象的引用,房子里可以住不同的人(搬來搬走)但是房東與這個房子的關(guān)系不能修改)
說明:在java中可能有多個修飾符同時修飾一個元素這多個修飾符之間可以任意交換次序:eg:下面的代碼是等價的:
int是變量類型,不是修飾符其位置不能改變
7.4.2 final的局部變量
被修飾final的局部變量與成員變量非常相似,不同之處是,局部final變量可以只聲明不初始化,一旦初始化了值不能改變,初始化時間只要在其使用之前就行,下面demo說明局部final變量:
運行結(jié)果:
這說明局部變量在使用之前不初始化是沒問題的,在19行和21行加上兩個初始化:
提示:關(guān)于局部引用的問題,與基本數(shù)據(jù)類型一致,可以不初始化,一旦初始化不可更改即指向哪個對象是不能改變的,但其所引用對象的成員是可以修改的。
7.5 static關(guān)鍵字
被static修飾過的成員與普通成員有很大的不同,Static關(guān)鍵字只能修飾成員,只要身份是成員都可以修飾eg:變量、方法、語句塊、內(nèi)部類
- 靜態(tài)的成員的基本使用
- 靜態(tài)成員的訪問
靜態(tài)最終成員變量
提示:訪問限制修飾符對靜態(tài)成員變量同樣有作用,規(guī)則與前面講的非靜態(tài)的相同7.5.1 靜態(tài)的成員
為什么要引入靜態(tài)的概念?原因主要有以下兩個:假定有一個實用的工具類,其中的一個方法總是以相同的方式運行,其行為與結(jié)果不依賴于對象的狀態(tài),eg:Math中的求絕對值的abs方法;因此當方法執(zhí)行與對象完全無關(guān)時,就不需要創(chuàng)建對象,完全可以要求類自身來運行這個方法。
- 另一種特殊情況,若想記錄某個類的所有對象的個數(shù)等關(guān)于這個類的所有對象的信息,這時必須需要一個依賴于類的而不是依賴于對象的變量來記錄此信息,否則將不能解決此問題;eg:依賴于對象的成員是不可能解決此問題的,因為每次創(chuàng)建對象時都會為其執(zhí)行相同的初始化工作
上述以相同方式運行的實用方法以及記錄同一個類所有對象的信息這兩種特殊情況,都是使用static來解決的。因此,用static關(guān)鍵字修飾的成員將屬于類,而不屬于任何特定的對象。也就是說,可以在根本沒有該類任何對象的時候使用被static修飾的成員
但若存在對象,靜態(tài)成員將被該類的所有對象共享,只有一份拷貝,而不像非靜態(tài)成員每個對象自己擁有一份拷貝eg:
運行結(jié)果:
對于非靜態(tài)成員變量selfCount,每個對象都有自己的拷貝,其屬于各個對象都從0加了一次1,所以打印1;
對于靜態(tài)成員變量count屬于類,類的所有對象共享一份拷貝所以三次,運行結(jié)果都為3;
7.5.2. 靜態(tài)成員的訪問
靜態(tài)成員屬于類,所以訪問的不需要創(chuàng)建對象 eg:
同一個類中可以不用類名點靜態(tài)變量名調(diào)用,但是在其他方法中就必須使用類名點靜態(tài)變量名,或者是相應(yīng)的對象引用,受到訪問限制級別的約束。
提示:實際開發(fā)中,提倡用類名來訪問靜態(tài)成員。
運行結(jié)果:
從下面兩個方面介紹同一個類中的靜態(tài)成員變量與非靜態(tài)成員變量成員之間的訪問。
“無法從靜態(tài)上下文中引用非靜態(tài)變量staticVar”的錯,這是因為main()方法是static的,而staticVar是非靜態(tài)成員,如下圖,因為靜態(tài)成員不依賴于該類的任何對象,所以當其所在的類加載成功后,就可以訪問其了,此時對象不一定存在,非靜態(tài)成員自然也不一定存在,靜態(tài)成員的生命周期比非靜態(tài)的長:
即使訪問時存在非靜態(tài)成員,靜態(tài)方法也不知道訪問的是哪一個對象的成員,因為靜態(tài)方法屬于類,非靜態(tài)成員屬于對象,所以靜態(tài)方法將不知道關(guān)于其所屬類對象的信息
提示:main()方法被定義為靜態(tài)的也是如此,其只是程序開始執(zhí)行的入口,不需要依賴任何對象,若要在靜態(tài)方法中訪問非靜態(tài)成員主要使用指向特定對象的引用即可:
運行結(jié)果:
而靜態(tài)方法訪問靜態(tài)成員時,自然是任何時候都沒問題,靜態(tài)成員屬于類只要類存在,靜態(tài)成員都將存在。
同理,靜態(tài)方法中不能使用this預(yù)定義對象引用的,即使后邊所操作的也是靜態(tài)成員也不行,因為this代表指向自己對象的引用,而靜態(tài)方法屬于類不屬于對象,其成功加載以后,對象還不一定存在,即使存在,也在不知道this指的是哪一個對象eg:
系統(tǒng)報“無法從靜態(tài)上下文中引用非靜態(tài)變量this”
2. 非靜態(tài)成員訪問靜態(tài)成員:
非靜態(tài)訪問靜態(tài)成員的時候,規(guī)則很簡單,非靜態(tài)成員的生命周期被靜態(tài)成員生命周期包含,因此,當非靜態(tài)成員存在的時候,靜態(tài)成員絕對存在,故非靜態(tài)方法可以隨時訪問靜態(tài)成員。eg:
運行結(jié)果:
7.5.3. 靜態(tài)最終成員變量
- 靜態(tài)最終變量的具體應(yīng)用
- 靜態(tài)最終成員變量的初始化
1、靜態(tài)最終變量的具體應(yīng)用:
沒有介紹java中如何實現(xiàn)常量,其實java中沒有一個直接的修飾符來實現(xiàn)常量,而是通過靜態(tài)最終成員變量的方式來實現(xiàn)的eg:
*1】static 屬于類,不必創(chuàng)建對象就能使用,因為常量不依賴于任何對象,final表示值不能改變;
2】一般用做常量的靜態(tài)最終變量訪問限制符都設(shè)置為public,因為常量允許所有類或?qū)ο笤L問*
其實前面的Math類中的PI與E常量就是Math類的最終成員變量
提示:雖然java中有const關(guān)鍵字,但不是用來聲明常量的,與C和C++不同,在java中const只是一個關(guān)鍵字,沒有任何意義,也不能出現(xiàn)在源代碼中
2、靜態(tài)最終成員變量的初始化【必須初始化】
前面的非靜態(tài)最終成員變量時講過,系統(tǒng)不會為其分配默認值,必須在構(gòu)造器完成之前對其初始化,對于靜態(tài)最終成員變量,系統(tǒng)也不會為其分配默認值,也必須初始化,但是其屬于類,是不能等到構(gòu)造器運行再初始化的因為類加載完之后其值必須可以使用
java中靜態(tài)最終成員變量的初始化要求在靜態(tài)語句塊結(jié)束之前必須完成,即java中靜態(tài)初始化有兩個時機:
eg:
static
{
const2=57;//初始化常量2
}這一塊稱為靜態(tài)語句塊,也是靜態(tài)成員的一種
提示:靜態(tài)語句塊在類加載的時執(zhí)行一次,可以將對類進行初始化的代碼寫在其中。
運行結(jié)果:
必須在靜態(tài)語句塊完成之前對靜態(tài)最終變量進行初始化。
第七章完~~~
【偉大的物理學家,一個有趣的人—-霍金在今天(2018年3月14號去世了),一顆偉大的恒心消失在天際。他幾乎陪著我們從小學開始到整個學習生涯的結(jié)束,他的對生活的態(tài)度,對科學的執(zhí)著,對人類的偉大貢獻使他將永遠活在我們的心中,愿他在天堂可以奔跑。】
總結(jié)
以上是生活随笔為你收集整理的java第七章学习笔记:访问控制---java世界的卫兵的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 2.1 随从图标的创建———自制卡牌游戏
- 下一篇: php算利润公式代码怎么写,以下利润的有