Java之二 面向對象
Java 語言的歷史和現狀
Java的類
對 象 實 例
實 例 變 量
new操 作 符
對象操作符——點
成 員 函 數 定 義
成 員 函 數 調 用
This 關鍵字
構 造 函 數(Constructor)
Java的類
視頻課堂:https://edu.csdn.net/course/play/8222
類是Java語言面向對象編程的基本元素,它定義了一個對象的結構和行為。在Java程序里,你要表達的概念封裝在某個類里。一個類定義了一個對象的結構和它的功能接口,功能接口稱為成員函數。當Java程序運行時,系統用類的定義創建類的實例,類的實例是真正的對象。類定義的一般形式如下:
classclassnameextendssuperclassname{
ypeinstance-variable1;
typeinstance-variable2;
typeinstance-variableN;
typemethodname1(parameter-list){
method-body;}
typemethodname2(parameter-list){
method-body;}
typemethodnameN(parameter-list){
method-body;}
}
這里,classname和superclassname是合法的標識符。關鍵詞extends用來表明classname是superclassname派生的子類。有一個類叫做Object,它是所有Java類的根。如果你想定義Object的直接子類,你可以省略extends子句,編譯器會自動包含它。下面是一個簡單的類的定義。classUniversity{}
對 象 實 例
類名可以作為變量的類型來使用,如果一個變量的類型是某個類,那么它將指向這個類的實例,稱為對象實例。所有對象實例和它們的類型(某個類的子類的實例都是相容的。就象可以把byte型的值賦給int型的變量一樣,你可以把Object的子類的任何實例賦給一個Object型的變量。一個實例是類模板的單獨的拷貝,帶有自己的稱為實例變量的數據集。每個實例也可以作為一個對象。當你定義一個變量的類型是某個類時,它的缺省值是null,null是Object的一個實例。對象null沒有值,它和整數0不同。下面這個例子中,聲明變量u的類型是類University。Universityu;這里,變量u的值是null。
實 例 變 量
Java通過在類定義的大括號里聲明變量來把數據封裝在一個類里。這里的變量稱為實例變量。下面的例子定義了一個叫做University的類,它有兩個實例變量:name和city。classUniversity{Stringname,city;}
new操 作 符
操作符new用來生成一個類的實例,下面這個例子生成了類University的一個實例,存放在變量u中。
Universityu=newUniversity();在此例中,變量u指向這個對象,但并不真正包含這個對象。你可以用多個變量指向同一個對象。下面的例子中,創建了一個University的對象,但創建了兩個指向它的變量。
Universityu=newUniversity();
Universityu2=u;
對u2所指向的對象的任何改動都會對u所指向的對象起作用,因為它們是同一個對象。對u和u2的賦值只是把它們指向這個對象,既沒有分配內存,也沒有復制這個對象的任何部分。對u的再賦值只是簡單地去掉了u和原來對象的聯系,并不影響對象本身,下面的例子說明了這種情況。
Universityu=newUniversity();
Universityu2=u;
u=null;
盡管u被賦值為null,u2仍指向原來由操作符new創建的對象。在前面的例子里,我們生成了一個對象并且指向了它兩次。這就允許兩個變量改變同一個對象。創建一個新的對象時,可直接對它的實例變量賦值。每個對象都有它所屬類的實例變量的拷貝,每個對象的實例變量都是和其他對象的實例變量分離的,所以改變一個對象的實例變量不會影響其他對象的實例變量。
下面的例子創建了兩個University的對象,并對它們分別賦值:
classTwoUniversity{
publicstaticvoidmain(Stringargs[]){
Universityu1=newUniversity();
Universityu2=newUniversity();
u1.name="北京大學";
u1.city="北京";
u2.name="清華大學";
u2.city="北京";
System.out.println("大學:"+u1.name+"城市:"+u1.city);
System.out.println("大學:"+u2.name+"城市:"+u2.city);
}}
這個例子創建了兩個University的對象,并且對它們的name、city分別賦了不同的值,這說明這兩個對象是真正分離的。
下面是該程序運行后的輸出結果。
C:\>javaTwoUniversity大學:北京大學城市:北京
大學:清華大學城市::北京
對象操作符——點
操作符點操作符用來接收一個對象的實例變量和成員函數。下面是用點操作符來接收實例變量的一般形式。
objectreference.variablename
這里objectreference是一個對象實例,variablename是這個對象里你想接收的實例變量。
下面的程序段說明了怎樣用點操作符來給實例變量賦值。
u.name="北京大學";
u.city="北京";
下面說明怎樣用點操作符來得到實例變量的值。
System.out.println("大學:"+u.name+"城市:"+u.city);
通過向類University里加入一個成員函數main,我們創建了一個完整的例子,它使用了new操作符來創建一個University,用點操作符來賦值,然后打印結果。
classUniversity{
Stringname,city;
publicstaticvoidmain(Stringargs[]){
Universityu=newUniversity();
u.name="北京大學";
u.city="北京";
System.out.println("大學:"+u.name+"城市:"+u.city);
}}
運行這個程序后,就會得到下面的結果。
C:\>javaTwoUniversity大學:北京大學城市:北京
成 員 函 數 定 義
成員函數,是類的功能接口,是類定義里的一個子程序,在類的定義里和實例變量處于同一級別。你必須通過一個類的實例來調用成員函數。成員函數可以不用點操作符而直接使用實例變量。成員函數帶有輸入參數,具有某種類型的返回值。成員函數定義的一般形式如下:
typemethodname(formal-parameter-list){
method-body;}
這里type指的是成員函數的返回值的類型,如果沒有返回值,就用無值(void類型。methodname可以是任何合法的標識符,但不能與當前的類名相同。formal-parameter-list是用逗號分隔的類型、標識符對的序列。如果沒有參數,括號里就是空的。還是用我們的University的例子,下面的成員函數用來初始化兩個實例變量。成員函數是在類的大括號內定義的,和實例變量所處的范圍相同。
classUniversity{
Stringname,city;
voidinit(Stringa,Stringb){
name=a;
city=b;
}}
注意,我們這里直接給name和city賦值,而沒有象以前那樣用u1.name。這是因為每個成員函數都在類的個別實例內執行。我們創建的類的實例具有它自己的實例變量,所以成員函數可直接使用它們。
成 員 函 數 調 用
可以用點操作符來調用一個類的實例的成員函數。成員函數調用的一般形式如下:
objectreference.methodname(parameter-list);
這里,objectreference是指向某個對象的變量,methodname是objectreference所屬類的一個成員函數,parameter-list是用逗號分隔的變量或表達式的序列,它們要與該成員函數的定義的參數個數及類型匹配。在這個例子里,我們可以對任何University對象調用成員函數init來給name和city賦值。下面的程序段說明了怎樣完成這個工作。
Universityu=newUniversity();
u.init("北京大學","北京");
這個例子創建了University的一個實例,存放在u中。通過點操作符來調用這個實例的init成員函數,把"北京大學"和"北京"分別傳遞給參數a和b。在init成員函數內部,name和city直接指向u所指向的對象的實例變量。把name賦值為"北京大學",city賦值為"北京",然后返回。在這個例子里,init被定義為無值(void返回類型)。在進行這個成員函數調用后,u指向這個name值和city值改變了的University對象。
this
Java有一個特殊的實例值叫this,它用來在一個成員函數內部指向當前的對象。在前面的例子里,我們調用u.init,一進入init成員函數內部,this就會指向u所指向的對象。在Java里,在同一個范圍定義兩個相同名字的局部變量是不可以的。有趣的是,局部變量、成員函數的參數可以和實例變量的名字相同。前面我們沒有用name和city作為成員函數init的參數名字,因為這樣它們在成員函數的范圍里就把實例變量name和city隱藏了,即name指向參數name,隱藏了實例變量name。this讓我們可以直接指向對象本身。下面是另一個版本的init,用name和city作為參數名字,用this來接收當前對象的實例變量。
voidinit(Stringname,Stringcity){
this.name=name;
this.city=city;
}
下面是帶有新的init初始成員函數的TwoUniversity例子。
classUniversity{
Stringname,city;
voidinit(Stringname,Stringcity){
this.name=name;
this.city=city;
}}
classTwoUniversityInit{
publicstaticvoidmain(Stringargs[]){
Universityu1=newUniversity();
Universityu2=newUniversity();
u1.init("北京大學","北京");
u2.init("清華大學","北京");
System.out.println("大學:"+u1.name+"城市:"+u1.city);
System.out.println("大學:"+u2.name+"城市:"+u2.city);
}}
構 造 函 數(Constructor)
每創建一個類的實例都去初始化它的所有變量是乏味的。如果一個對象在被創建時就完成了所有的初始工作,將是簡單的和簡潔的。因此,Java在類里提供了一個特殊的成員函數,叫做構造函數(Constructor)。一個構造函數是對象被創建時初始對象的成員函數。它具有和它所在的類完全一樣的名字。一旦定義好一個構造函數,創建對象時就會自動調用它。構造函數沒有返回類型,即使是void類型也沒有。這是因為一個類的構造函數的返回值的類型就是這個類本身。構造函數的任務是初始一個對象的內部狀態,所以用new操作符創建一個實例后,立刻就會得到一個清楚、可用的對象。下面這個例子里,用構造函數取代了成員函數init。
classUniversity{
Stringname,city;
University(Stringname,Stringcity){
this.name=name;
this.city=city;
}}
classUniversityCreate{
publicstaticvoidmain(Stringargs[]){
Universityu=newUniversity("北京大學","北京");
System.out.println("大學:"+u.name+"城市:"+u.city);
}}
new語句中類名后的參數是傳給構造函數的。
Java 面向對象的分析
深入分析面向對象實例
與面向過程的思想做一個比較,面向過程是指,我們考慮問題時,以一個具體的流程(事務過程)為單位,考慮它的實現過程;面向對象是指,我們考慮問題時,把任何東西看做是對象,以對象為單位,考慮它的屬性及方法。
好比一個木匠在做一把凳子,假如他是面向過程的木匠,他會想到制作凳子的過程。“先做什么呢?凳子腿?凳子板?用什么工具呢?”。假如他是一個面向對象的木匠,他會把所有的東西看做成對象,“凳子腿,凳子板兩個對象。凳子腿有屬性,長方體的,長度,寬度是多少厘米,有方法釘釘子。凳子板的屬性,正方形,邊長是多少厘米等等問題。”這樣的話,面向對象的木匠會依據這些條件。將一個凳子組裝在一起。最終目的是做成一個凳子,用什么思想方法去做,是值得研究的。
通過剛才的例子,我們會有一種感覺,面向對象的木匠會對事務量化的分析,用“數學”的方法處理問題似的。似乎他更具有進步意義。面向對象的思想也確實有著他的先進之處,它把世界上的所有事務看做成為對象,這樣的話更貼近于現實世界,這樣的話使得邏輯清楚,誰看報告的時候也喜歡看條理清楚的報告啊。這樣使得面向對象的軟件開發,成為上世紀90年代直到現在的主流開發技術。傳統開發方法存在以下問題:
1.軟件重用性差
重用性是指同一事物不經修改或稍加修改就可多次重復使用的性質。軟件重用性是軟件工程追求的目標之一。誰愿意來往返回的寫一件事情呢。
2.軟件可維護性差
軟件工程強調軟件的可維護性,強調文檔資料的重要性,規定最終的軟件產品應該由完整、一致的配置成分組成。在軟件開發過程中,始終強調軟件的可讀性、可修改性和可測試性是軟件的重要的質量指標。實踐證實,用傳統方法開發出來的軟件,維護時其費用和成本仍然很高,其原因是可修改性差,維護困難,導致可維護性差。
3.開發出的軟件不能滿足用戶需要
用傳統的結構化方法開發大型軟件系統涉及各種不同領域的知識,在開發需求模糊或需求動態變化的系統時,所開發出的軟件系統往往不能真正滿足用戶的需要。
現在的面向對象的思想已經擴展到很多方面,如數據庫系統、交互式界面、應用結構、應用平臺、分布式系統、網絡治理結構、CAD技術、人工智能等領域。而且他指的是面向對象分析(OOA),面向對象設計(OOD),面向對象編程(OOP),這一套過程了。
下面我們來看一下,經常用到的重要概念,也就是java語言的的OOP特性,這是對于OOP而言的,不含前面的OOA和OOD的。因為是初學嘛,還沒有學到怎么分析和設計呢。Java的OOP有三大特性:封裝、繼續、多態。
封裝的概念已經在第4節課說過了,我們講的是,它用權限修飾符private使得屬性不能被外界訪問,像是人的五臟六腑怎么能讓人隨意的碰呢?人的這個屬性也是要封裝的。如有再不明白,請訪問我們的技術論壇。
說一下輕易理解的繼續:
當一個類是另一個類的特例時,這兩個類之間具有父子類的關系。子類繼續了父類的方法和屬性,就是說子類可以重用父類中的這部分代碼。比如:轎車是車的一個特例。轎車是車的子類。就是說,轎車繼續了車的一切特性。繼續用要害字extends表示。
實踐:
//這是基類
publicclassChe{
privateintwheel=4;
publicintgetWheel(){
returnwheel;
}?? }
publicclassJiaocheextendsChe{
privateStringpinpai="桑塔納";
publicStringgetPinpai(){
returnpinpai;
}?? }
publicclassTestche{
publicstaticvoidmain(String[]args){
Jiaochecar=newJiaoche();
intwheels=car.getWheel();//調用基類的方法
StringPinpal=car.getPinpai();//調用本身的方法
System.out.println("車有"+wheels+"個輪子");
System.out.println("轎車的品牌是"+Pinpal);
}?? }
注意:java語言與C++不同只可以從一個父類繼續哦(單繼續)。
還有就是最難理解的多態了,我們下次課講面向對象的多態性。
使用Java 包的概念
java中“包”的引入的主要原因是java本身跨平臺特性的需求。因為java中的所有的資源也是以文件方式組織,這其中主要包含大量的類文件需要組織管理。java中同樣采用了目錄樹形結構。雖然各種常見操作系統平臺對文件的管理都是以目錄樹的形式的組織,但是它們對目錄的分隔表達方式不同,為了區別于各種平臺,java中采用了"."來分隔目錄。
package和import
打包和導入包
Java程序編譯的類被放在包內,要訪問類就要給出類所屬的包名,來指明類是在哪一個包中,以便能夠找到該類。一個包中有許多類,同時還可以有子包。如我們會在應用程序中經常用到Systen.out.println()方法來講結果輸出。參看Java的包,我們知道System是一個類,它屬于lang包;同時,lang又屬于java包。指明類的位置是,當沒有用import語句,要訪問System類就首先要指明在哪一個包中(用VJ++編寫程序時,每一個源文件都默認用import語句將java.lang包中的所有類引入,所以可以直接用類名System來訪問類)。Java用小圓點"."來說明包的這種包含關系,例如:
lang.System表示System類屬于子包lang,java.lang表示子包lang是屬于java包,java包是最外層包即根包。這樣java.lang.System已經完全表明了System包的層次關系,根據這種關系,就能夠找到System類并訪問它了。java.lang.System稱為訪問類System的全限定名,用全限定名就可以訪問類了,要訪問類需要完全說明包的層次關系,例如java是最外層包,lang.System不是類System的全限定名,不能用它來訪問類System。
當類有其靜態成員變量和靜態成員方法時,靜態變量和靜態方法能夠被類直接訪問,out是System類的靜態成員,out有一個方法println(),下面介紹怎樣訪問類的靜態成員。
能夠用類的全限定名訪問類,同樣可以通過類成員的全限定名訪問類的成員,如System的成員out是一個對象,out的全限定名為java.lang.System.out;同時,對象out又有println()方法,則println()方法的全限定名為:java.lang.System.out.println(),通過該名可以訪問println()方法。
下面的程序是使用全限定名來訪問方法的實例:
mainclass{
publicstaticvoidmain(Stringarg[]){
java.lang.Stringhello=newjava.lang.String("helloworld!");
java.lang.System.out.println(hello);
}}
類的全限定名與類在文件系統中的存儲結構即目錄有對應關系,例如java.lang.Sytem表示類System存儲在lang目錄中,lang是java的子目錄,java是根目錄。java.lang對應的目錄為:\java\lang
當包的層次很多,而類處于較內層的包時,則類的全限定名較長,例如有下面的層次的包:school.department.class.group
有名為fly的類在包group中,model類在包department中,則:
fly的全限定名為:school.department.class.group.fly
model的全限定名為:school.department.model
顯然用這樣的名字來操作類,將是非常麻煩的。因此,Java提供了import語句。下面介紹包操作語句import和package。
2.1包操作語句import
指明將要訪問的類所在的包,以便在當前目錄找不到時,在import語句指明的包中尋找,若找不到類將出現編譯錯誤。
包語句import的一般格式:
import類名;
我們知道,訪問類可以用全限定名來訪問,當要訪問的類在同一個包中時,這時可以直接用要訪問的類的類名代替全限定名進行操作。
例如,我們定義了兩個類firstclass、secondclass,它們都屬于mylopbag.smallbag包,在secondclass類中可以直接用firstclass代替全限定名mylafgebag.Smallbag.firstclass類。
當所要訪問的類不在同一個包中時,就需要使用全限定名。全限定名往往很長,為此用import語句來減短訪問類時用的名字。下面介紹import語句的兩種用法。
用import語句。指明要訪問的類位置。我們知道,類System在子包lang中,子包lang在最外層包即根包java中,我們引入如下語句
第一種用法:importJava.lang.*;
表示引入java.lang包內的所有類,當要訪問包中的類時,直接用類名,如直接用類名為System訪問類System.同時,類System中定義了Prinln()方法,用System.println()就可以調用方Prinln();
第二種用法:imnortjava.lang.System;
表示只引入java.lang包中的System類,訪問包java.lang中的類時.只有System類能用類名來訪問,包中的其他類需要全限定名來訪問。
System.println()調用println()方法,其它類的成員則需要用成員的全限定來訪問。用該語句能減少訪問類時搜索的路徑,提高運行的效率。
要注意的是import語句引入的是類,不能是子包,例如
importjava.lang.*;
該語句在編譯時會出錯,因為lang是java的一個子包,不是類,而VJ++認為lang是一個類,這樣會出現找不到lang類的提示。用戶在編程時,系統默認在每個源文件頭加入了下面的import語句:
importjava.lang.*;
因此在用到這條語句時,編程時無需用說明。import語句在源文件的前面,一個源文件可以有多條import語句。import語句在package語句后面。import語句與C語言的include語句有本質的區別。import語句只指明要用到的類所在的位置,以便能在用到時可以加載;而C語言用include語句將要用的文件包含在源文件中,作為源文件編譯成一個模塊。這體現了Java語言的特點,用戶只需要將模塊編譯一次。當用戶在編寫另一個模塊用到已經編譯的模塊時,只要告訴編譯程序它的位置,如用全限定名或者用import語句,編譯程序無需再一次編譯已經編譯的模塊,就能夠將源文件編譯通過。
2.2包操作語句Package
Package語句必須是源文件的第一條語句,且一個源文件只能有一條該語句。Package語句的格式為:
Packape包名;
例如:
Packagemyrotbag;
也可以是:
Packagemyrootbag.mysubbag;
常用的java包
在Java中,包的概念和目的都與其他語言的函數庫非常類似,所不同的只是其中封裝的是一組類。為了開發和重用的方便,我們可以將寫好的程序類整理成一個個程序包。下面是Java預設包中主要的幾個:
·??????????????java.lang提供基本數據類型及操作。
·??????????????java.util提供高級數據類型及操作。
·??????????????java.io提供輸入/輸出流控制。
·??????????????java.awt提供圖形窗口界面控制。
·??????????????java.awt.event提供窗口事件處理。
·??????????????java.net提供支持Internet協議的功能。
·??????????????java.applet提供實現瀏覽器環境中Applet的有關類和方法。
·??????????????java.sql提供與數據庫連接的接口。
·??????????????java.rmi提供遠程連接與載入的支持。
·??????????????java.security提供安全性方面的有關支持。
我們可以引用這些包,也可以創建自己的包。
1、包的聲明
為了聲明一個包,首先必須建立一個相應的目錄結構,子目錄與包名一致。然后在需要放入該包的類文件開頭聲明包,形式為:
package包名;這樣,在這個類文件中定義的所有類就都被裝入到您所希望的包中了,例如:
packagebookexample;
classA{
……
}
classBextendsA{
……
}
publicclassOverrideExample{
……
}
不同的程序文件內的類也可以同屬于一個包,只要在這些程序文件前都加上同一個包的說明即可。
2、包的使用
在Java中,為了裝載使用已編譯好的包,通常可使用以下3種方法:
在要引用的類名前帶上包名作為修飾符。例如:
bookexample.AobjA=newbookexample.A();
其中bookexample是包名,A是包中的類名,objA是類的對象。
(2)在文件開頭使用import引用包中的類。例如:
importbookexample.A;
classExample{
AobjA=newA();
}
同樣,bookexample是包名,A是包中的類,objA是創建的A類對象。
(3)在文件前使用import引用整個包。例如:
importbookexample.*;
classExample{
AobjA=newA();
}
bookexample整個包被引入,A是包中的類,objA是創建的A類對象。
在使用包時,可以用點“.”表示出包所在的層次結構,用“.*”表示該目錄結構下的所有內容。
需要指出的是,java.lang這個包無需顯式引用,它總是被編譯器自動調入。使用包時還要特別注意系統classpath路徑的設置情況,它需要將包名對應目錄的父目錄包含在classpath路徑中,否則編譯時會出錯,提示用戶編譯器找不到指定的類。
使用Java 的API文檔
API文檔的概念
在做c#練習時,如果我們遇到不會的對象或方法,會去查詢msdn;那么在java中我們會查詢java的api文檔。
Java的api文檔里包含了java所有的基礎類庫;
API文檔的使用
Java中文API文檔的chm格式文檔。
實踐問題:
1.你以前編寫過面向過程的程序嗎?比如:類似的腳本語言是面向過程的嗎?
2.能不能從你的現實生活中分別提取一個面向對象和面向過程的實例?
小結:
在本章中,我們主要學習了:
u????Java面向對象的特征
u????面向對象的分析方法
英語詞匯:
英文??????????????????? 全文?????????????????????????? 中文
Constructor?????? Constructor????????? 構造函數
Extends?????? Extends?????????? 繼承,擴展
Package??????? Package?????????????? 包
Import????????????????? Import???????????????????????? 導入
練習項目:
針對一個銀行的取款,分別編寫一個面向對象和面向過程的兩個程序代碼?
Java 面向對象編程
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。