面向對象編程基礎
1.1 面向對象概述
在程序開發初期,大家使用的是結構化開發語言,也就是面向過程(opp),但隨着市場需求劇增,軟件的規模也越來越大,結構化語言的弊端也暴露出來。
開發周期無休止的拖延,軟件質量也越來越差。
為了更好的適應市場,有人就開始以另一種開發思想引入程序中,也就是面向對象的開發思想(oop)。
面向對象思想是人類最自然的一種思考方式,他將所有預處理的問題抽象為對象,同時了解這些對象具有哪一些對應的屬性以及行為,以解決這些對象面臨的一些實際問題,面向對象設計實質上就是對現實世界的對象進行建模操作。或者說把現實世界的操作虛擬到程序中去
1.2 對象
對象,是一個抽象概念,英文稱為“Object”,表示存在的事物。通俗的來說就是世間萬物皆對象!現實世界中肉眼可見的一種事物都是對象,對象是事物存在的實體,例如:人、手機、電腦。為了大家能簡單的理解,只要現實世界中看得到的實物都是一個對象。
1.2.1 對象的組成
一個實體(對象)可以划分兩個部分,一個是描述外觀和功能。那么在程序里關於實體(對象)描述外觀的稱為“屬性”;實體(對象)的功能稱之為“行為”或“方法”,也就是實體(對象)執行的動作。例如:人的性別是描述這個實體(對象)的,人能行走也能吃飯和學習是執行的動作。
實體(對象)由屬性和行為組成,也就是實體(對象)的外觀和功能。
1.3 類
類是封裝對象的屬性和行為的載體,反過來說具有相同屬性和行為的一類實體被稱之為類(簡單的理解也可以是分類)。例如:大雁群就可以看做是大雁類,因為每一只大雁都有相同的嘴、翅膀和爪等外貌特性;同時每一只大雁也會睡覺、飛行、覓食等行為。所以就可以進行分類用程序角度來說的話這一群大雁就是一個大雁類。而大雁群中的每一只大雁都是大雁類的一個對象。
從上面兩張流程圖我們知道大雁群中的每一只大雁都具備一樣的外觀描述和行為(功能),那么我們就可以把這個實體(對象)稱之為這個分類下的對象或者實體。
總結:類可以理解為分類,是抽象的。而對象就是實體,可以看得到摸得着的。
1.3.1 OPP程序設計特點簡單介紹
面向對象程序設計具有以下三個通用特點:
√封裝性
√繼承性
√多態性
a).封裝
封裝是面向對象編程的核心思想。也就是將對象的特征和行為封裝起來,其載體就是類,類通常會隱藏其實現細節,這就是封裝的思想。也就是說現實生活中的物品或商品你只要負責使用就ok,其他的你可以不管。例如:使用手機打電話,只要你打通電話就行,具體內部怎么實現無需知道。
總結:程序中采用封裝的思想主要是保證了類內部數據結構的完整性和安全性,使用該類的用戶不能輕易的直接操作次數據結構,只能操作類允許公開的數據。這樣一來就避免了外部操作對內部數據的影響,提高了程序的可維護性。
b) 繼承
繼承是每一門計算機語言不可少的機制,主要作用就是利用繼承機制使新建的類可以建立在原有類的基礎之上。在使用或者重寫原有類的行為或者功能(程序里叫成員方法)以及訪問原有類的特征(也就是類的成員變量)。我們可以稱新類為子類,原有類為父類。舉個例子:如果類A是類B的父類,而類B是類C的父類,那么也可稱類C是類A的子類,類C是從類A基礎而來。同時在java中,關於類的繼承是單一繼承的,也就是說,一個子類只能擁有一個父類,一個父類可以有多個子類。總而言之,繼承是在代碼中實現重復利用的重要手段,子類通過繼承,復用父類特征和行為的同時又添加了子類特有的特征和行為。
c) 多態
將父類對象應用於子類的特征就是多態。多態通俗理解就是多種形態,但每一個實體(對象)還是具備了父類的特征和行為。
2.類與對象
上面我們認識類的時候就已經講過,類是我們封裝實體(對象)的外觀特征(屬性)和行為的載體,也就是說這個實體(對象)有哪一些外觀描述和功能都可以在類里面進行封裝描述
2.1 類的聲明
語法:
public class 類名稱 { //類的主體... }
注意:
- 如果類文件中只有一個類時,文件名必須與類名保持一致;
- 一個java文件中只能有一個public類;
- 如果類文件中不止一個類,文件名必須與public類名一致;
- 如果文件中不止一個類,而且沒有public類,文件可與任意類名一致;
java類名的命名規則:
- 類名應該以下划線(_)或者字母開頭,最好以字母開頭;
- 第一個字母最好大寫,如果類名由多個單詞組成,則每個單詞的首字母最好都大寫;
- 類名不能為java中的關鍵字,例如:String、this、double、int等;
- 類名不能包括任何嵌入的空格或點號,以及除了下划線(_)和美元符號($)字符之外的特殊符號。
2.2 a 成員變量
java中實體(對象)的特征(屬性)也稱之為成員變量,成員變量的定義和普通變量定義是一樣的。
數據類型 變量名稱 [ = 值 ];
注意:代碼中的[ = 值]表示可選內容,也就是說定義變量時可以為其賦值也可以不賦值。
我們來舉一個例子,例如鳥類==》Bird類,成員變量對應於類對象屬性,鳥都有翅膀、爪子、嘴巴、羽毛...而這一些都是描述鳥的外觀也就是對象的屬性,所以Bird應該有四個成員變量:wing、claw、beak、feather。
//定義一個Bird鳥類 public class Bird{ String wing; //翅膀 String claw; //爪子 String beak; //嘴巴 String feather; //羽毛 }
分析:上面 代碼使用關鍵字class定義類,類名是Bird,同時在Bird類中定義了4個成員變量,成員變量的類型可以設置java中合法的數據類型,說到底成員變量和普通變量是一樣的,成員變量也可以設置初始值,也可以不設置初始值。不設置初始值就會有一個默認值。
數據類型 | 默認值 | 詳細說明 |
float、double | 0.0 | 浮點零 |
char | '' | 空格字符 |
boolean | false | 邏輯符 |
引用類型,如:String | null | 空值 |
int、byte、short、long | 0 | 0值 |
上面是我們在定義類時使用的一些數據類型以及對應的默認值
2.2 b 成員方法
2.2.1 成員方法的定義
成員方法對應類對象(實體)的行為或者功能,主要是用來定義類可執行的操作,行為或者功能就是一系列語句組成的代碼塊。
語法:
[權限修飾符] [返回值類型] 方法名 ([參數類型 參數名]){ //方法體--> 一系列代碼 return 返回值; }
分析:
- 權限修飾符可以是private、public、protected中的任意一個,也可以不寫,主要來控制方法(行為)的訪問權限。
- 返回值類型用來指定方法(行為)返回數據的類型,可以是任何類型,如果方法不需要返回值則可以使用void關鍵字。
- 一個成員方法(行為)可以有參數也可以沒有參數,同時參數是對象也可以是基本數據類型。
class Person{ String name = "張三";//成員變量也稱之為類對象屬性
//定義一個方法,作用是做一個自我介紹 //不需要返回 public void showInfo(){ System.out.println(name); } }
public class Per{ public static void main(String[] args){ Person p = new Person(); p.showInfo();//輸出張三 } }
注意:
方法的定義必須是在某個類的里面 ,也就是在類中;同時定義方法如果沒有給定權限訪問修飾符,該方法的默認權限也缺少,也就是只能在本類以及同一個包中的類進行訪問。
如果定義的方法有設置了返回值,則方法里必須使用return關鍵字返回一個指定類型的數據,並且返回類型要與方法返回值的類型一致。
2.2.2 成員方法的參數
在調用方法時可以給該方法傳遞一個或者多個值,傳遞給方法的值叫做實參,在方法內部,接受實參的變量叫作形參,形參的聲明語法和變量的聲明語法是一樣的。在java中方法的參數主要有以下三種:
- 值參數
- 引用參數
- 不定長參數
【值參數:】
值參數是實參與形參之間按值傳遞,當使用值參數方法被調用時,編譯器為形參分配儲存空間,然后將對應的實參的值復制到形參中,由於是值類型的傳遞方式,所以在方法中對值類型的形參和修改不會影響實參。
例:書架上有30本書,箱子里有40本書,現吧書架上的書全部放入箱子后,使用帶參數的成員方法統計箱子里書的總數。
public class Book{ public static void mian(String []){ Book b = new Book(); int num1 = 30; int num2 = 40; int box = b.add(num1,num2); System.out.println("箱子書總數為:"+ box); } //統計箱子中所有書本 public int add(int num1, int num2){ int box = 0; box = num1+num2; return box; } }
【引用參數:】
在給方法傳遞參數時,參數的類型數組或者其它引用類型,那么,在方法中對參數的修改會反映到原有的數組或者其他的引用類型上,這種類型的方法參數就叫做引用參數。
現將1、10、100美元存入double數組中,使用引用參數將數組的美元轉化成RMB,例1:6.903
public class Rate{ public static void main(String[] args){ double[] arr = {1, 10, 100}; //輸出數組中的美鈔 for(int i = 0; i < arr.length; i++){ System.out.println(arr[i] + "美元"); } //調用方法change change(arr); //再次輸出數組中數據 for(int i = 0; i < arr.length; i++){ System.out.println(arr[i] + "元"); } } //定義一個方法,參數為一維數組(形參) public void change(double[] arr){ for(int i = 0; i < arr.length; i++){ arr[i] *= 6.903; //換算成RMB } } }
【不定長參數:】
在聲明方法的時候,如有若干個相同類型的參數,則可以定義不定長參數的成員方法。
public class Scal{ public static void main(String[] args){ int num1=20,num2=42,num3=32,num4=329,num5=329; Scal s = new Scal(); int sum1 = s.add(num1, num2); //只計算二個數值的和 int sum2 = s.adds(num1,num2,num3,num4,num5); System.out.println("sum1=" + sum1); System.out.println("sum2=" + sum2); } //計算二個數之和 public int add(int num1, int num2){ return num1 + num2; } //計算一系列整數之和 public int adds(int... num){ int sum = 0; for(int i = 0; i < x.length; i++){ sum += x[i]; } //返回和 return sum; } }
2.3 局部變量
局部變量從字面意思來理解就是在一定范圍有效。
定義:成員方法內部定義的變量,那么這個變量就是局部變量。
分析:局部變量在方法執行時被創建在方法執行結束后就會被銷毀。同時局部變量在使用時必須進行賦值操作或者初始化,否則會出現編譯錯誤。
public class Demo{ public static void main(String[] args){ Demo d = new Demo(); d.sayHello(); } //說hello public void sayHello(){ String name = "Java"; //是在方法sayHello體內聲明的所以是局部變量 System.out.println(name); } }
2.4 構造方法
2.4.1 無參構造方法定義
在類中除了有成員方法之外還有一個特殊類型的方法,那就是構造方法。構造方法是一個類與類同名的方法,我們實體就是通過構造方法來創建的。也就是說每當類實例化一個對象時,類都會自動調用構造方法。
- 構造方法沒有返回值類型,也不能定義void
- 構造方法的名稱要與本類的名稱相同
- 構造方法主要作用是完成初始化工作,也能把定義對象的參數傳給對象成員
分析:
在定義一個類的構造方法時,構造方法是沒有返回值(一定要記住),同時也要知道構造方法與普通方法沒有返回值的方式不同,普通方法返回值的方法用public void 方法名()形式定義,但構造方法並不需要void關鍵字進行修飾。
public class 類名 { //構造方法 public 類名() { } }
注意:
- public 修飾符關鍵字不能少
- 類名一定要保持一致
2.4.2 定義有參構造方法
在對構造方法中可以為成員變量進行賦值,這樣當實例化一個本類的對象時,相應的成員變量也會被初始化。類中沒有定義構造方法時,編譯器會自動創建一個不帶參數的構造方法作為默認。
public class Book { //書名 String name; //定義一個有參數的構造方法 public Book(String str){ name = str; } }
注意:
- public修飾符關鍵字不能少
- 類名一定要保持一致
- 構造方法的參數可以是一個或多個
分析:
如果在類中定義的構造方法是有參構造方法,編譯器就不會為類自動生成一個默認無參構造方法,此時當調用無參構造方法實例化一個對象時,編譯器就會報錯。因此要記住,只有在類中沒有定義構造方法時,編譯器才會去自動生成一個不帶參數的構造方法。
public class Per{ public static void main(String[] args){ Per p = new Per(); p.sayHello("張三", "男"); } //無參構造方法 public Per(){ } //介紹自己 public void sayHello(String name, String sex){ System.out.println("我的名字"+ name + ",性別是" + sex); } }
public class Per{ String username; //成員變量 String agender; //成員變量 public static void main(String[] args){ } //有參構造方法 public Per(String name, String sex){ username = name; agender = sex; } public void sayHello(){ System.out.println("我的名字是:" + username + ",性別為:" + agender); } }
2.5 this關鍵字
this關鍵字在方法體內表示當前類的對象。類是對象的載體,把通過類可以創建出很多的對象,那么當創建的對象去調用方法時,被調用的方法體內有this關鍵字,那么這個方法體內的this就是當前對象自己本身。
關於this的三種用法:
1.區分成員變量和局部變量
public class Demo{ public static void main(String[] args){ Demo2 d = new Demo2("張三", 32); d.sayHello(); } } class Demo2{ String name; //名字 int age; //年齡 public Demo2(String name, int age){ name = name; age = age; } //說出自己個人信息 public void sayHello(){ System.out.println("我的名字是" + name + ",年齡為" + age); } }
輸出結果為:我的名字是null,年齡為0
在我們構造方法中如果沒有使用this來作為變量區分,那么name = name 和 age = age 都是局部變量在操作。也就是局部變量name = 局部變量name,所以成員變量name就一直沒有操作。
public class Demo{ public static void main(String[] args){ Demo2 d = new Demo2("張三", 32); d.sayHello(); } } class Demo2{ String name; //名字 int age; //年齡 public Demo2(String name, int age){ this.name = name; this.age = age; } //說出自己個人信息 public void sayHello(){ System.out.println("我的名字是" + name + ",年齡為" + age); } }
輸出結果為:我的名字是張三,年齡為32
總結:this在構造方法中,如果參數名稱和成員變量一樣,則可以使用this來進行區分。
2.構造方法中的使用
public class People{ String name; //姓名 int age; //年齡 String agender; //性別 public static void main(String[] args){ People p = new People("張三"); p.sayHello(); } public People(String name, String agender, int age){ this.name = name; this.agender = agender; this.age = age; System.out.println("這是類的第一個構造方法"); } public People(String name, String agender){ this.name = name; this.agender = agender; System.out.println("這是類的第二個構造方法"); } public People(String name){ this.name = name; System.out.println("這是類的第三個構造方法"); } public void sayHello(){ System.out.println("name=" + name + ",agender=" + agender + ",age=" +age); } }
輸出結果為:
這是類的第三個構造方法
name=張三,agender=null,age=0
如果在類構造方法中使用this關鍵字后:
public class People{ String name; //姓名 int age; //年齡 String agender; //性別 public static void main(String[] args){ People p = new People("張三"); p.sayHello(); } public People(String name, String agender, int age){ this.name = name; this.agender = agender; this.age = age; System.out.println("這是類的第一個構造方法"); } public People(String name, String agender){ this(name, agender, 32); this.name = name; this.agender = agender; System.out.println("這是類的第二個構造方法"); } public People(String name){ this(name, "男"); this.name = name; System.out.println("這是類的第三個構造方法"); } public void sayHello(){ System.out.println("name=" + name + ",agender=" + agender + ",age=" +age); } }
輸出結果為:
這是類的第一個構造方法
這是類的第二個構造方法
這是類的第三個構造方法
name=張三,agender=男,age=32
3.表示當前對象
public class Demo{ String name; int age; public static void main(String[] args){ Demo d = new Demo("張三", 32); System.out.println(d.name + d.age); } public Demo(String name, int age){ this.name = name; this.age = age; } }
分析:
this表示當前調用對象也就是對象“d”,那么構造方法中的this.name就完全等價於d.name = “張三”。
3 static關鍵字
在代碼中使用static關鍵字修飾的變量、方法、常量都被稱為靜態變量、方法、常量,也可以稱之為類的靜態成員。
靜態成員的使用不需要實例化對象就可以使用,使用的方法也很簡單就是【類名.家庭成員】
3.1 靜態成員
public class StaticStu { public static String name = ""; public static void main(String[] args){ name = "張三"; //等價於StaticStu.name = "張三" System.out.println(name); } } //輸出的結果為:張三
注意:
在類中使用靜態成員可以直接使用,也是不需要實例化。
3.2靜態方法
public class StaticStu { public static void main(String[] args){ StaticStu.SayHello(); } public static void SayHello(){ System.out.println("深夜了"); } } //輸出結果為:深夜了
注意:
定義和使用跟變量一樣,都是static進行修飾,也不需要實例化就可直接使用
3.3 靜態代碼塊
類有類的成員,那么類也有着自己的行為,那就是類的代碼塊,也稱之為靜態代碼塊。主要作用和構造方法雷同,是用來為為類做一些初始化工作。
public class StaticStu { static { System.out.println("我是類的代碼塊,我初始化了"); } public static void main(String[] args){ } } //輸出結果為:我是類的代碼塊,我初始化了
注意:
類有代碼塊那么對象也有代碼塊,直接是以{}即可。