淺談Java實(shí)現(xiàn)面向?qū)ο缶幊蘪ava oop
一、對(duì)象的綜述
面向?qū)ο缶幊蹋∣OP)具有多方面的吸引力。對(duì)管理人員,它實(shí)現(xiàn)了更快和更廉價(jià)的開(kāi)發(fā)與維護(hù)過(guò)程。對(duì)分析與設(shè)計(jì)人員,建模處理變得更加簡(jiǎn)單,能生成清晰、易于維護(hù)的設(shè)計(jì)方案。對(duì)程序員,對(duì)象模型顯得如此高雅和淺顯。此外,面向?qū)ο蠊ぞ咭约皫?kù)的巨大威力使編程成為一項(xiàng)更使人愉悅的任務(wù)。每個(gè)人都可從中獲益,至少表面如此。
所有編程語(yǔ)言的最終目的都是解決企業(yè)又或者人在現(xiàn)實(shí)生活中所遇到的問(wèn)題,最初我們的程序可能長(zhǎng)這樣“11111100001”,相信大家都不會(huì)陌生,只是大家沒(méi)這么子去敲過(guò)代碼。再后來(lái)出現(xiàn)了匯編語(yǔ)言,匯編語(yǔ)言便是對(duì)基礎(chǔ)機(jī)器語(yǔ)言(二進(jìn)制)的少量抽象,再到后來(lái)出現(xiàn)了許多“命令式”語(yǔ)言(如FORTRAN、BASIC和C),這些語(yǔ)言便是對(duì)匯編語(yǔ)言的一種抽象。這些語(yǔ)言都有了長(zhǎng)足的進(jìn)步,但它們的抽象原理依然要求我們著重考慮計(jì)算機(jī)的結(jié)構(gòu),而考慮的不是要解決的問(wèn)題的本身結(jié)構(gòu)。在機(jī)器與實(shí)際要解決的問(wèn)題之間,程序員必須建立起一種聯(lián)系,這個(gè)過(guò)程要求人們付出較大的精力,使得程序代碼很難編寫(xiě),寫(xiě)出來(lái)的代碼又很難理解,要花較大的代價(jià)進(jìn)行維護(hù)。
面向?qū)ο蟮某绦虮愫芎玫慕鉀Q了這一問(wèn)題,程序員可利用程序來(lái)表達(dá)實(shí)際問(wèn)題中的元素,我們便將這些元素在程序中的表示稱為“對(duì)象”。我們可以根據(jù)現(xiàn)實(shí)中的問(wèn)題來(lái)靈活配置對(duì)象,以便與特定的問(wèn)題配合。與之前的語(yǔ)言相比,這無(wú)疑是一種更加靈活、更加強(qiáng)大的語(yǔ)言抽象??傊甇OP允許我們根據(jù)問(wèn)題來(lái)描述問(wèn)題,而不是根據(jù)問(wèn)題在機(jī)器中的方案。與現(xiàn)實(shí)世界中的“對(duì)象”或者“物體”相比,編程對(duì)象與它們也存在共通的地方:它們都有自己的特征和行為。
二、什么是對(duì)象
通過(guò)上面的文字或許大家已經(jīng)有些明白什么是對(duì)象了吧?而上面的文字也是對(duì)對(duì)象的一種比較深入的理解,而我們最常見(jiàn)的理解方式無(wú)非是:對(duì)象(object)是任何看得見(jiàn)、摸得著、感覺(jué)得到,可以獲得的東西,有自己的標(biāo)識(shí)的任何東西。對(duì)象是某一類的事物的具體個(gè)例。比如這輛汽車(chē)、這個(gè)人、這間房子、這張桌子、這株植物、這張支票、這件雨衣,概括來(lái)說(shuō)就是:萬(wàn)物皆對(duì)象。
在這里給大家摘錄一些句子,希望看過(guò)的人能夠花時(shí)間去思考一下:
①“對(duì)象一般以域的形式包含數(shù)據(jù),通常稱作屬性;以程序的形式包含代碼,通常稱作方法”。②“對(duì)象在域中儲(chǔ)存自身狀態(tài)并通過(guò)方法暴露自身行為”。③“每個(gè)對(duì)象就如一個(gè)小型電腦——它有狀態(tài),并且它提供操作,你可以調(diào)用執(zhí)行”。④“一個(gè)類包含了存放數(shù)值的數(shù)據(jù)域和操作數(shù)值的的方法”。⑤“一個(gè)對(duì)象就是儲(chǔ)存某些類型的值的內(nèi)存空間”。⑥“一個(gè)對(duì)象包含一些私有內(nèi)存空間和一些操作”。
三、面向?qū)ο蟪绦蛟O(shè)計(jì)方法
(1)所有東西都是對(duì)象。可將對(duì)象想象成一種新型變量;它保存著數(shù)據(jù),但可要求它對(duì)自身進(jìn)行操作。理論上講,可從要解決的問(wèn)題身上提出所有概念性的組件,然后在程序中將其表達(dá)為一個(gè)對(duì)象。(2)程序是一大堆對(duì)象的組合;通過(guò)消息傳遞,各對(duì)象知道自己該做些什么。為了向?qū)ο蟀l(fā)出請(qǐng)求,需向那個(gè)對(duì)象“發(fā)送一條消息”。更具體地講,可將消息想象為一個(gè)調(diào)用請(qǐng)求,它調(diào)用的是從屬于目標(biāo)對(duì)象的一個(gè)子例程或函數(shù)。(3)每個(gè)對(duì)象都有自己的存儲(chǔ)空間,可容納其他對(duì)象。或者說(shuō),通過(guò)封裝現(xiàn)有對(duì)象,可制作出新型對(duì)象。所以,盡管對(duì)象的概念非常簡(jiǎn)單,但在程序中卻可達(dá)到任意高的復(fù)雜程度。(4)每個(gè)對(duì)象都有一種類型。根據(jù)語(yǔ)法,每個(gè)對(duì)象都是某個(gè)“類”的一個(gè)“實(shí)例”。其中,“類”(Class)是“類型”(Type)的同義詞。一個(gè)類最重要的特征就是“能將什么消息發(fā)給它?”。(5)同一類所有對(duì)象都能接收相同的消息。這實(shí)際是別有含義的一種說(shuō)法。由于類型為“圓”(Circle)的一個(gè)對(duì)象也屬于類型為“形狀”(Shape)的一個(gè)對(duì)象,所以一個(gè)圓完全能接收形狀消息。這意味著可讓程序代碼統(tǒng)一指揮“形狀”,令其自動(dòng)控制所有符合“形狀”描述的對(duì)象,其中自然包括“圓”。這一特性稱為對(duì)象的“可替換性”,是OOP 最重要的概念之一。(6)一些語(yǔ)言設(shè)計(jì)者認(rèn)為面向?qū)ο蟮某绦蛟O(shè)計(jì)本身并不足以方便解決所有形式的程序問(wèn)題,提倡將不同的方法組合成“多形程序設(shè)計(jì)語(yǔ)言”。
四、對(duì)象的使用
下面讓我們以電燈泡為例:
在這個(gè)例子中,類型/類的名稱是 Light,可向 Light 對(duì)象發(fā)出的請(qǐng)求包括包括打開(kāi)( on)、關(guān)閉( off)、變得更明亮( brighten )或者變得更暗淡( dim)。通過(guò)簡(jiǎn)單地聲明一個(gè)名字( lt),我們?yōu)?Light 對(duì)象創(chuàng)建了一個(gè)“句柄”。然后用 new 關(guān)鍵字新建類型為 Light 的一個(gè)對(duì)象。再用等號(hào)將其賦給句柄。為了向?qū)ο蟀l(fā)送一條消息,我們列出句柄名( lt),再用一個(gè)句點(diǎn)符號(hào)( .)把它同消息名稱( on)連接起來(lái)。從中可以看出,使用一些預(yù)先定義好的類時(shí),我們?cè)诔绦蚶锊捎玫拇a是非常簡(jiǎn)單和直觀的。
五、封裝
封裝,即隱藏對(duì)象的屬性和實(shí)現(xiàn)細(xì)節(jié),僅對(duì)外公開(kāi)接口,控制在程序中屬性的讀和修改的訪問(wèn)級(jí)別;將抽象得到的數(shù)據(jù)和行為(或功能)相結(jié)合,形成一個(gè)有機(jī)的整體,也就是將數(shù)據(jù)與操作數(shù)據(jù)的源代碼進(jìn)行有機(jī)的結(jié)合,形成“類”,其中數(shù)據(jù)和函數(shù)都是類的成員。封裝的目的是增強(qiáng)安全性和簡(jiǎn)化編程,使用者不必了解具體的實(shí)現(xiàn)細(xì)節(jié),而只是要通過(guò)外部接口,以特定的訪問(wèn)權(quán)限來(lái)使用類的成員。隱藏之后,外部程序就不能接觸和改變那些細(xì)節(jié),所以不用擔(dān)心自己的類會(huì)受到非法修改,可確保它們不會(huì)對(duì)其他程序造成影響。
封裝的原則:
1. 將不需要對(duì)外提供的內(nèi)容都隱藏起來(lái);
2. 把屬性都隱藏,提供公共方法對(duì)其訪問(wèn)。
簡(jiǎn)單示例代碼:
package com.alanlee;public class Student { //屬性私有化,避免屬性被直接使用和修改 private Integer age; //對(duì)外提供公有的方法用來(lái)獲取對(duì)象的屬性值 public Integer getAge() { return age; } //對(duì)外提供公有的方法,可以對(duì)對(duì)象的屬性進(jìn)行控制,避免不合法的操作 public void setAge(Integer age) { if(age > 0 && age < 100){ this.age =age; }else{ System.out.println('輸入的年齡不合法!'); } } public static void main(String[] args) { Student stu = new Student(); //賦值 stu.setAge(10); //取值并打印 System.out.println(stu.getAge()); }}
六、繼承
我們費(fèi)盡心思做出一種數(shù)據(jù)類型后,假如不得不又新建一種類型,令其實(shí)現(xiàn)大致相同的功能,那會(huì)是一件非常令人灰心的事情。但若能利用現(xiàn)成的數(shù)據(jù)類型,對(duì)其進(jìn)行“克隆”,再根據(jù)情況進(jìn)行添加和修改,情況就顯得理想多了。“繼承”正是針對(duì)這個(gè)目標(biāo)而設(shè)計(jì)的。但繼承并不完全等價(jià)于克隆。在繼承過(guò)程中,若原始類(正式名稱叫作基礎(chǔ)類、超類或父類)發(fā)生了變化,修改過(guò)的“克隆”類(正式名稱叫作繼承類或者子類)也會(huì)反映出這種變化。在 Java 語(yǔ)言中,繼承是通過(guò) extends 關(guān)鍵字實(shí)現(xiàn)的。
使用繼承時(shí),相當(dāng)于創(chuàng)建了一個(gè)新類。這個(gè)新類不僅包含了現(xiàn)有類型的所有成員(盡管private 成員被隱藏起來(lái),且不能訪問(wèn)),但更重要的是,它復(fù)制了基礎(chǔ)類的接口。也就是說(shuō),可向基礎(chǔ)類的對(duì)象發(fā)送的所有消息亦可原樣發(fā)給衍生類的對(duì)象。根據(jù)可以發(fā)送的消息,我們能知道類的類型。這意味著衍生類具有與基礎(chǔ)類相同的類型!為真正理解面向?qū)ο蟪绦蛟O(shè)計(jì)的含義,首先必須認(rèn)識(shí)到這種類型的等價(jià)關(guān)系。
由于基礎(chǔ)類和衍生類具有相同的接口,所以那個(gè)接口必須進(jìn)行特殊的設(shè)計(jì)。也就是說(shuō),對(duì)象接收到一條特定的消息后,必須有一個(gè)“方法”能夠執(zhí)行。若只是簡(jiǎn)單地繼承一個(gè)類,并不做其他任何事情,來(lái)自基礎(chǔ)類接口的方法就會(huì)直接照搬到衍生類。這意味著衍生類的對(duì)象不僅有相同的類型,也有同樣的行為,這一后果通常是我們不愿見(jiàn)到的。
有兩種做法可將新得的衍生類與原來(lái)的基礎(chǔ)類區(qū)分開(kāi)。第一種做法十分簡(jiǎn)單:為衍生類添加新函數(shù)(功能)。這些新函數(shù)并非基礎(chǔ)類接口的一部分。進(jìn)行這種處理時(shí),一般都是意識(shí)到基礎(chǔ)類不能滿足我們的要求,所以需要添加更多的函數(shù)。這是一種最簡(jiǎn)單、最基本的繼承用法,大多數(shù)時(shí)候都可完美地解決我們的問(wèn)題(添加特定的方法,特殊的方法)。第二種做法是改變基礎(chǔ)類一個(gè)現(xiàn)有函數(shù)的行為(重寫(xiě)父類的方法)。
簡(jiǎn)單示例代碼:
public class Animal { private String name; private int id; public Animal(String myName, int myid) { name = myName; id = myid; } public void eat(){ System.out.println(name+'正在吃'); } public void sleep(){ System.out.println(name+'正在睡'); } public void introduction() { System.out.println('大家好!我是' + id + '號(hào)' + name + '.'); }}
public class Penguin extends Animal { public Penguin(String myName, int myid) { super(myName, myid); } }
public class Mouse extends Animal { public Mouse(String myName, int myid) { super(myName, myid); } }
Java是單繼承的,一個(gè)類只能繼承一個(gè)父類。
七、多態(tài)
多態(tài)是同一個(gè)行為具有多個(gè)不同表現(xiàn)形式或形態(tài)的能力,多態(tài)就是同一個(gè)接口,使用不同的實(shí)例而執(zhí)行不同操作,多態(tài)性是對(duì)象多種表現(xiàn)形式的體現(xiàn)。
多態(tài)的優(yōu)點(diǎn):
1. 消除類型之間的耦合關(guān)系 2. 可替換性 3. 可擴(kuò)充性 4. 接口性 5. 靈活性 6. 簡(jiǎn)化性多態(tài)存在的三個(gè)必要條件:
繼承 重寫(xiě) 父類引用指向子類對(duì)象當(dāng)使用多態(tài)方式調(diào)用方法時(shí),首先檢查父類中是否有該方法,如果沒(méi)有,則編譯錯(cuò)誤;如果有,再去調(diào)用子類的同名方法。
簡(jiǎn)單示例代碼:
public class Test { public static void main(String[] args) { show(new Cat()); // 以 Cat 對(duì)象調(diào)用 show 方法 show(new Dog()); // 以 Dog 對(duì)象調(diào)用 show 方法 Animal a = new Cat(); // 向上轉(zhuǎn)型 a.eat(); // 調(diào)用的是 Cat 的 eat Cat c = (Cat)a; // 向下轉(zhuǎn)型 c.work(); // 調(diào)用的是 Cat 的 catchMouse } public static void show(Animal a) { a.eat(); // 類型判斷 if (a instanceof Cat) { // 貓做的事情 Cat c = (Cat)a; c.work(); } else if (a instanceof Dog) { // 狗做的事情 Dog c = (Dog)a; c.work(); } }}abstract class Animal { abstract void eat();}class Cat extends Animal { public void eat() { System.out.println('吃魚(yú)'); } public void work() { System.out.println('抓老鼠'); }}class Dog extends Animal { public void eat() { System.out.println('吃骨頭'); } public void work() { System.out.println('看家'); }}
八、抽象類
設(shè)計(jì)程序時(shí),我們經(jīng)常都希望基礎(chǔ)類只為自己的衍生類提供一個(gè)接口。也就是說(shuō),我們不想其他任何人實(shí)際創(chuàng)建基礎(chǔ)類的一個(gè)對(duì)象,只對(duì)上溯造型成它,以便使用它們的接口。為達(dá)到這個(gè)目的,需要把那個(gè)類變成“抽象”的—— 使用 abstract 關(guān)鍵字。若有人試圖創(chuàng)建抽象類的一個(gè)對(duì)象,編譯器就會(huì)阻止他們。這種工具可有效強(qiáng)制實(shí)行一種特殊的設(shè)計(jì)。
亦可用 abstract 關(guān)鍵字描述一個(gè)尚未實(shí)現(xiàn)的方法—— 作為一個(gè)“根”使用,指出:“這是適用于從這個(gè)類繼承的所有類型的一個(gè)接口函數(shù),但目前尚沒(méi)有對(duì)它進(jìn)行任何形式的實(shí)現(xiàn)。”抽象方法也許只能在一個(gè)抽象類里創(chuàng)建。繼承了一個(gè)類后,那個(gè)方法就必須實(shí)現(xiàn),否則繼承的類也會(huì)變成“抽象”類。通過(guò)創(chuàng)建一個(gè)抽象方法,我們可以將一個(gè)方法置入接口中,不必再為那個(gè)方法提供可能毫無(wú)意義的主體代碼。
interface(接口)關(guān)鍵字將抽象類的概念更延伸了一步,它完全禁止了所有的函數(shù)定義?!敖涌凇笔且环N相當(dāng)有效和常用的工具。另外如果自己愿意,亦可將多個(gè)接口都合并到一起(不能從多個(gè)普通 class 或abstract class 中繼承)。比如上面的示例代碼就將父類以及父類的方法進(jìn)行了抽象,因?yàn)楦割惒⒉恍枰鋈魏螌?shí)際的事情。
九、對(duì)象在哪里
對(duì)象保存在內(nèi)存堆。一種常規(guī)用途的內(nèi)存池(也在 RAM 區(qū)域),其中保存了 Java 對(duì)象。和堆棧不同,“內(nèi)存堆”或“堆”( Heap)最吸引人的地方在于編譯器不必知道要從堆里分配多少存儲(chǔ)空間,也不必知道存儲(chǔ)的數(shù)據(jù)要在堆里停留多長(zhǎng)的時(shí)間。因此,用堆保存數(shù)據(jù)時(shí)會(huì)得到更大的靈活性。要求創(chuàng)建一個(gè)對(duì)象時(shí),只需用new 命令編制相關(guān)的代碼即可。執(zhí)行這些代碼時(shí),會(huì)在堆里自動(dòng)進(jìn)行數(shù)據(jù)的保存。當(dāng)然,為達(dá)到這種靈活性,必然會(huì)付出一定的代價(jià):在堆里分配存儲(chǔ)空間時(shí)會(huì)花掉更長(zhǎng)的時(shí)間。
到此這篇關(guān)于淺談Java實(shí)現(xiàn)面向?qū)ο缶幊蘪ava oop的文章就介紹到這了,更多相關(guān)Java實(shí)現(xiàn)面向?qū)ο缶幊虄?nèi)容請(qǐng)搜索好吧啦網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持好吧啦網(wǎng)!
相關(guān)文章:
1. python中scrapy處理項(xiàng)目數(shù)據(jù)的實(shí)例分析2. Hybris在idea中debug配置方法詳解3. Python AutoCAD 系統(tǒng)設(shè)置的實(shí)現(xiàn)方法4. 在idea中為注釋標(biāo)記作者日期操作5. jsp cookie+session實(shí)現(xiàn)簡(jiǎn)易自動(dòng)登錄6. .NET Core Web APi類庫(kù)內(nèi)嵌運(yùn)行的方法7. .NET6使用ImageSharp實(shí)現(xiàn)給圖片添加水印8. ASP.NET MVC實(shí)現(xiàn)橫向展示購(gòu)物車(chē)9. ASP.NET MVC使用Boostrap實(shí)現(xiàn)產(chǎn)品展示、查詢、排序、分頁(yè)10. .net如何優(yōu)雅的使用EFCore實(shí)例詳解
