詳細(xì)聊一聊java中封裝的那點(diǎn)事
什么是封裝
什么是封裝呢?我們先來(lái)看一段代碼
class Student { public String name; private int age; } public class Test4 { public static void main(String[] args) { // 引用變量student指向該新創(chuàng)建的對(duì)象 Student student = new Student(); // 實(shí)例化對(duì)象 student.age = 12; // 通過(guò)引用變量名.成員變量來(lái)訪問(wèn)Student類中的成員變量 } }
讓我們運(yùn)行一下
好家伙,報(bào)錯(cuò)了,為什么當(dāng)age被private修飾后就不能訪問(wèn)了呢?
??private的字面意思就是私人的、私有的,在java中被private修飾的變量只能在當(dāng)前類中訪問(wèn),就像上面的Student類中的age變量,它就只能在Student這個(gè)類中被訪問(wèn),不能在Test4這個(gè)類中訪問(wèn)。
這樣有什么用呢?當(dāng)然有用??
這樣可以防止age其他地方被隨意的修改,比如把a(bǔ)ge賦值成一個(gè)負(fù)數(shù),那合適嗎、正常嗎?
??那name成員變量前的public又是什么意思呢?public就是公共的、公開的,被public修飾的成員變量不管在那都是可以被訪問(wèn)的。我們之前在定義成員變量時(shí),好像在變量前沒(méi)有像public、private這樣的東東呀!那時(shí)我們也能通過(guò)對(duì)象引用一個(gè)一個(gè)的訪問(wèn)那些成員變量呀?
??這時(shí)我們就有必有引入封裝這個(gè)概念了
??封裝將類的某些信息隱藏在類內(nèi)部,不允許外部程序直接訪問(wèn),只能通過(guò)該類提供的方法來(lái)實(shí)現(xiàn)對(duì)隱藏信息的操作和訪問(wèn)。例如:一臺(tái)計(jì)算機(jī)內(nèi)部極其復(fù)雜,有主板、CPU、硬盤和內(nèi)存, 而一般用戶不需要了解它的內(nèi)部細(xì)節(jié),不需要知道主板的型號(hào)、CPU 主頻、硬盤和內(nèi)存的大小,于是計(jì)算機(jī)制造商將用機(jī)箱把計(jì)算機(jī)封裝起來(lái),對(duì)外提供了一些接口,如鼠標(biāo)、鍵盤和顯示器等,這樣當(dāng)用戶使用計(jì)算機(jī)就非常方便。
??封裝的特點(diǎn):
- 只能通過(guò)規(guī)定的方法訪問(wèn)數(shù)據(jù)。
- 隱藏類的實(shí)例細(xì)節(jié),方便修改和實(shí)現(xiàn)。
??實(shí)現(xiàn)封裝的具體步驟如下:
- 修改屬性的可見性來(lái)限制對(duì)屬性的訪問(wèn),一般設(shè)為 private。
- 為每個(gè)屬性創(chuàng)建一對(duì)賦值(setter)方法和取值(getter)方法,一般設(shè)為 public,用于屬性的讀寫。
- 在賦值和取值方法中,加入屬性控制語(yǔ)句(對(duì)屬性值的合法性進(jìn)行判斷)。
??我們剛才提到的private其實(shí)就是一種封裝,被private修飾的只能本類才能訪問(wèn),其他類都訪問(wèn)不了,如此就對(duì)信息進(jìn)行了隱藏。
??那么我們?nèi)绾卧L問(wèn)被private修飾的成員變量呢?
??如果外界想要訪問(wèn)私有屬性,需要提供一些使用public修飾的公有方法。其中包括用于獲取屬性值的getXxx方法和設(shè)置屬性值的setXxx方法 。
class Student { public String name; private int age; public int getAge() { // 這些專門用來(lái)訪問(wèn)設(shè)置屬性的方法一般用public來(lái)修飾 return age; } public void setAge(int age) { this.age = age; } } public class Test4 { public static void main(String[] args) { Student student = new Student(); student.name = "張三"; // 被public修飾的可以在其他類中隨意訪問(wèn)(但不太安全,有風(fēng)險(xiǎn)) System.out.println("姓名:" + student.name); System.out.println("======這是分割線========"); student.setAge(19); // 通過(guò)專門的設(shè)置屬性的setAge()方法來(lái)賦值(安全,不能隨意修改) System.out.println("年齡:" + student.getAge());//通過(guò)專門的訪問(wèn)屬性的getAge()來(lái)打印 } }
從運(yùn)行結(jié)果來(lái)看,姓名、年齡都被成功的賦值并打印了。但因?yàn)樗麄兦懊娴脑L問(wèn)修飾限定符不一樣,所以對(duì)年齡、姓名的訪問(wèn)權(quán)限也不同,訪問(wèn)方式自然也不同了。
封裝拓展之包
??而如果你沒(méi)任何修飾限定符,編譯器默認(rèn)就是包訪問(wèn)權(quán)限;想要理解什么是包訪問(wèn)權(quán)限,你首先要理解什么是包。
包的概念
??在面向?qū)ο篌w系中,提出了一個(gè)軟件包的概念,即:為了更好的管理類,把多個(gè)類收集在一起成為一組,稱為軟件 包。
??這其實(shí)有點(diǎn)類似于我們電腦中不同的文件夾。
在Java中也引入了包,包是對(duì)類、接口等的封裝機(jī)制的體現(xiàn),是一種對(duì)類或者接口等的很好的組織方式,比如:一 個(gè)包中的類不想被其他包中的類使用。
包還有一個(gè)重要的作用:在同一個(gè)工程中允許存在相同名稱的類,只要處在不同的包中即可。
?? 我們可以IDEA里嘗試創(chuàng)建一個(gè)包:
??然后輸入你包的名字,比如demo1,然后回車
??就新創(chuàng)建了一個(gè)新的文件夾demo1
??在這個(gè)文件夾(也就是這個(gè)包中)我們就可以添加我們的java文件了
什么是包訪問(wèn)權(quán)限
包訪問(wèn)權(quán)限就是只要我們?cè)偻粋€(gè)包下面就可以訪問(wèn)互相訪問(wèn),即使他們不在同一個(gè)java文件里面
為了更清楚一點(diǎn),我們來(lái)實(shí)踐一下
??可以看到我們?cè)趖estdemo1中定義了一個(gè)變量a,成員變量a的訪問(wèn)權(quán)限是包訪問(wèn)權(quán)限
看來(lái)只要這個(gè)變量是包訪問(wèn)權(quán)限,那么在一個(gè)包下變量可以互相訪問(wèn)呀!
那么如果不在一個(gè)包下呢
看來(lái)就無(wú)法訪問(wèn)了??
??這下你對(duì)包訪問(wèn)權(quán)限是否有了一個(gè)初步的理解了呢?
??從上面的例子我們也不難發(fā)現(xiàn),
被private修飾的變量只能在同一個(gè)類中訪問(wèn)默認(rèn)的包訪問(wèn)權(quán)限可以在同一個(gè)包下、不同的類中來(lái)訪問(wèn)而public則是哪都能訪問(wèn)
????????????????????????????????
什么是靜態(tài)成員
靜態(tài)成員就是被關(guān)鍵字static修飾的成員變量或者成員方法。
??而static又是什么呢?老規(guī)矩,先來(lái)看一段代碼
class Student { private String name; private int age; public static String school; // 定義一個(gè)靜態(tài)成員變量 public Student(String name, int age) { this.name = name; this.age = age; // 想一下我下面為什么不用this.school來(lái)訪問(wèn) System.out.println("姓名:" + this.name + " 年齡:" + this.age + " 學(xué)校:" + school); } } public class Test4 { public static void main(String[] args) { // 奇怪吧!我還沒(méi)實(shí)例化對(duì)象呢?怎么就能對(duì)類中的成員變量賦值呢? Student.shool = "茶啊二中"; Student student1 = new Student("張三", 17); Student student2 = new Student("李四", 16); Student student3 = new Student("王五", 18); } }
??可以看出,上面我們創(chuàng)建的三個(gè)學(xué)生對(duì)象都在同一個(gè)學(xué)校,所以為了節(jié)省內(nèi)存空間,我們其實(shí)不需要讓創(chuàng)建的每個(gè)對(duì)象都儲(chǔ)存一份學(xué)校這個(gè)屬性??,只要有一個(gè)內(nèi)存儲(chǔ)存學(xué)校這個(gè)屬性,然后大家共享就好了。
下面先來(lái)看共享的一個(gè)例子:
class Student { private String name; private int age; public static String school; // 定義一個(gè)靜態(tài)成員變量 public Student(String name, int age) { this.name = name; this.age = age; // 想一下我下面為什么不用this.school來(lái)訪問(wèn) System.out.println("姓名:" + this.name + " 年齡:" + this.age + " 學(xué)校:" + school); } } public class Test4 { public static void main(String[] args) { // 奇怪吧!我還沒(méi)實(shí)例化對(duì)象呢?怎么就能對(duì)類中的成員變量賦值呢? Student.shool = "茶啊二中"; Student student1 = new Student("張三", 17); Student student2 = new Student("李四", 16); Student student3 = new Student("王五", 18); } }
什么情況,竟然沒(méi)報(bào)錯(cuò)?
??我想你在看了上面的代碼,肯定有很多疑惑吧!別著急我們慢慢來(lái)揭開static這層神秘的面試
在 Java 中,被 static 修飾的成員,稱之為靜態(tài)成員,也可以稱為類成員,其不屬于某個(gè)具體的對(duì) 象,是所有對(duì)象所共享的 。 如果把shool這個(gè)屬性設(shè)置為static,那school這個(gè)靜態(tài)變量將會(huì)單獨(dú)儲(chǔ)存在靜態(tài)區(qū),而不是和他所在的對(duì)象一起存儲(chǔ)在堆區(qū)。什么意思呢?咱們用圖說(shuō)話:
如上圖所示,實(shí)例化的對(duì)象student1和student2共享school這個(gè)成員屬性。
從上圖我們也可以看出靜態(tài)區(qū)的school其實(shí)是不依賴對(duì)象的,因?yàn)樗径紱](méi)在對(duì)象所在的堆區(qū),所以我們可以直接通過(guò):類名.school來(lái)訪問(wèn)這個(gè)成員變量。
哈哈,是不是有有點(diǎn)暈??。就快完了,加油!
??被static修飾的變量稱為靜態(tài)變量,被static修飾的方法稱為靜態(tài)方法
??不管靜態(tài)變量還是靜態(tài)方法都不屬于某個(gè)具體的對(duì)象,而是整個(gè)類的屬性。我們下面嘗試用一下靜態(tài)方法,看看他和普通方法的區(qū)別在哪里?
?? 可以看出程序在 " run() "這個(gè)地方報(bào)錯(cuò)了,為啥在靜態(tài)方法中不能調(diào)用普通方法呢?
??我們前面說(shuō)過(guò)this這個(gè)關(guān)鍵字,其實(shí)在這里報(bào)錯(cuò)就和this引用有關(guān)。我們先來(lái)回顧一下this
(?´?`?)(?´?`?)(?´?`?)(?´?`?)(?´?`?)
??this的深入:1.在每一個(gè)非靜態(tài)方法的內(nèi)部,都有一個(gè)this,相當(dāng)于一個(gè)句柄,由編譯器隱示添加。method(參數(shù)列表)可以看成是method(類名 this,參數(shù)列表)
??在面向?qū)ο笾校蓡T屬性必須由對(duì)象調(diào)用,所以在方法內(nèi)部,每一個(gè)成員其實(shí)都有一個(gè)this.”前綴,當(dāng)對(duì)象調(diào)用這個(gè)方法的時(shí)候,編譯器會(huì)把該對(duì)象傳遞給方法(也就是常說(shuō)的“this指向調(diào)用該方法的當(dāng)前對(duì)象”),編譯器會(huì)將其編譯為method(對(duì)象,實(shí)參列表)。
?? 而在一個(gè)靜態(tài)方法內(nèi)部,由于靜態(tài)方法是屬于類的,被每個(gè)類的實(shí)例所共享,所以沒(méi)有this句柄,當(dāng)然就不能在靜態(tài)方法中訪問(wèn)非靜態(tài)的成員(屬性和方法)??,而具體在編譯器會(huì)怎么看愣,編譯器會(huì)說(shuō)哪個(gè)對(duì)象調(diào)用了成員,我都找不到這個(gè)對(duì)象??,然后它就會(huì)大吼一句“還有誰(shuí)?。。?rdquo;,最后報(bào)錯(cuò)??。
??所以說(shuō),靜態(tài)方法里面調(diào)用的必須是不依賴對(duì)象的成員變量和成員方法——即靜態(tài)方法和靜態(tài)變量,當(dāng)我們把上面的run普通方法改成靜態(tài)方法,編譯器自然就不報(bào)錯(cuò)了。
總結(jié)一下:
被static修飾的成員變量或方法,被所有對(duì)象所共享靜態(tài)變量和靜態(tài)方法可以直接被類名所調(diào)用靜態(tài)方法只能調(diào)用靜態(tài)成員,不能調(diào)用非靜態(tài)成員。非靜態(tài)方法可以調(diào)用靜態(tài)成員,也可以調(diào)用非靜態(tài)成員
好了,以上就們就對(duì)靜態(tài)成員有了一個(gè)初步的認(rèn)識(shí)。
到此這篇關(guān)于java中封裝的文章就介紹到這了,更多相關(guān)java封裝詳解內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Spring Batch輕量級(jí)批處理框架實(shí)戰(zhàn)
本文主要介紹了Spring Batch輕量級(jí)批處理框架實(shí)戰(zhàn),文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-10-10SpringBoot獲取Request和Response方法代碼解析
這篇文章主要介紹了SpringBoot獲取Request和Response方法代碼解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-11-11javascript checkbox全選和反選的簡(jiǎn)單實(shí)現(xiàn)
這篇文章主要介紹了javascript checkbox全選和反選的簡(jiǎn)單實(shí)現(xiàn)的相關(guān)資料,需要的朋友可以參考下2017-05-05Java ArrayList與Vector和LinkedList的使用及源碼分析
ArrayList、Vector、LinkedList類均在java.util包中,均為可伸縮數(shù)組,即可以動(dòng)態(tài)改變長(zhǎng)度的數(shù)組。ArrayList 和 Vector都是基于存儲(chǔ)元素的Object[] array來(lái)實(shí)現(xiàn)的,它們會(huì)在內(nèi)存中開辟一塊連續(xù)的內(nèi)存來(lái)存儲(chǔ)2022-11-11Java線程池ThreadPoolExecutor源碼深入分析
ThreadPoolExecutor作為java.util.concurrent包對(duì)外提供基礎(chǔ)實(shí)現(xiàn),以內(nèi)部線程池的形式對(duì)外提供管理任務(wù)執(zhí)行,線程調(diào)度,線程池管理等等服務(wù)2022-08-08Mybatis?TypeHandler接口及繼承關(guān)系示例解析
這篇文章主要為大家介紹了Mybatis?TypeHandler接口及繼承關(guān)系示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-02-02Java適配器模式的實(shí)現(xiàn)及應(yīng)用場(chǎng)景
適配器模式是Java中一種常用的設(shè)計(jì)模式,它通過(guò)將一個(gè)類的接口轉(zhuǎn)換成客戶端所期望的另一種接口來(lái)實(shí)現(xiàn)不同接口之間的兼容性。適配器模式主要應(yīng)用于系統(tǒng)的接口不兼容、需要擴(kuò)展接口功能以及需要適應(yīng)不同環(huán)境的場(chǎng)景2023-04-04