1. 面向?qū)ο笏枷?/strong>
1.1 面向?qū)ο笏枷胍?/strong>
前面我們講過數(shù)組,當(dāng)有多個數(shù)組都需要遍歷時,我們可以將遍歷的代碼封裝到方法中,需要遍歷時,就調(diào)用相應(yīng)的方法即可,提高代碼的復(fù)用性。在對數(shù)組遍歷的基礎(chǔ)上繼續(xù)增加需求,比如獲取最值,數(shù)值逆序等,同樣需要將這些功能封裝到相應(yīng)的方法中。這樣繼續(xù)封裝會發(fā)現(xiàn)方法越來越多,于是就想能不能將這些方法繼續(xù)進行封裝呢?通過前面的講解我們知道類是可以存放方法的,所以,我們就考慮使用類封裝來這多個方法,將來再做數(shù)組的操作時,不用去找具體的方法,先找到這個類,然后使用這個類中的方法。這就是面向?qū)ο笏枷氲木幊谭绞健?/p>
1.2 面向過程思想概述
我們來回想一下,這幾天我們完成一個需求的步驟:首先是搞清楚我們要做什么,然后在分析怎么做,最后我們再代碼體現(xiàn)。一步一步去實現(xiàn),而具體的每一步都需要我們?nèi)崿F(xiàn)和操作。這些步驟相互調(diào)用和協(xié)作,完成我們的需求。
在上面的每一個具體步驟中我們都是參與者,并且需要面對具體的每一個步驟和過程,這就是面向過程最直接的體現(xiàn)。
那么什么是面向過程開發(fā)呢? 面向過程開發(fā),其實就是面向著具體的每一個步驟和過程,把每一個步驟和過程完成,然后由這些功能方法相互調(diào)用,完成需求。
面向過程的代表語言:C語言,強調(diào)的是每一個功能的步驟
1.3 面向?qū)ο笏枷敫攀?/strong>
當(dāng)需求單一,或者簡單時,我們一步一步去操作沒問題,并且效率也挺高??呻S著需求的更改,功能的增多,發(fā)現(xiàn)需要面對每一個步驟很麻煩了,這時就開始思索,能不能把這些步驟和功能在進行封裝,封裝時根據(jù)不同的功能,進行不同的封裝,功能類似的封裝在一起。這樣結(jié)構(gòu)就清晰了很多。用的時候,找到對應(yīng)的類就可以了。這就是面向?qū)ο蟮乃枷搿=酉聛砦覀兛纯疵嫦驅(qū)ο蟮降资鞘裁?
面向?qū)ο笏枷敫攀觯好嫦驅(qū)ο笫腔诿嫦蜻^程的編程思想,強調(diào)的是對象,然后由對象去調(diào)用功能。
面向?qū)ο笏枷胩攸c
- 是一種更符合我們思想習(xí)慣的思想
- 可以將復(fù)雜的事情簡單化
- 將我們從執(zhí)行者變成了指揮者,角色發(fā)生了轉(zhuǎn)換
舉例:
(1) 買電腦:
?
面向過程:我的了解電腦--了解我自己的需求--找對應(yīng)的參數(shù)信息--去中關(guān)村買電腦--討價還價--買回電腦
面向?qū)ο螅何抑牢乙I電腦 -- 班長去給我買 -- 班長就買回來了
(2) 洗衣服:
面向過程:把衣服脫下--找一個盆--放點洗衣粉--加點水--把衣服扔進去--搓一搓--清洗衣服--擰干--晾起來
面向?qū)ο螅喊岩路撓?-打開全自動洗衣機--扔進去--一鍵即可--晾起來
(3) 吃飯:
面向過程:去超市買菜--摘菜--洗菜--切菜--炒菜--盛起來--吃
面向?qū)ο螅荷巷埖瓿燥垼?-服務(wù)員(點菜)--廚師(做菜)--服務(wù)員(端菜)--吃
1.4 面向?qū)ο箝_發(fā),設(shè)計,特征
面向?qū)ο箝_發(fā):就是不斷的創(chuàng)建對象,使用對象,指揮對象做事情。
面向?qū)ο笤O(shè)計:其實就是在管理和維護對象之間的關(guān)系。
面向?qū)ο筇卣?/p>
- 封裝(encapsulation)
- 繼承(inheritance)
- 多態(tài)(polymorphism)
2. 類與對象及其使用
2.1 類與對象的關(guān)系
我們學(xué)習(xí)編程語言,就是為了模擬現(xiàn)實世界的事物,實現(xiàn)信息化。比如:去超市買東西的計費系統(tǒng),去銀行辦業(yè)務(wù)的系統(tǒng)。
我們?nèi)绾伪硎疽粋€現(xiàn)實世界事物呢:
- 屬性 就是該事物的描述信息
- 行為 就是該事物能夠做什么
- 舉例:學(xué)生事物
我們學(xué)習(xí)的Java語言最基本單位是類,所以,我們就應(yīng)該把事物用一個類來體現(xiàn)。
類:是一組相關(guān)的屬性和行為的集合
對象:是該類事物的具體體現(xiàn)
舉例:類 學(xué)生,對象班長就是一個對象
PS
類:可以理解為構(gòu)造對象的一個藍圖或者模版,是抽象的概念
對象:是以類為模型創(chuàng)建的具體實例,是對類的一種具體化。
2.2 類的定義
現(xiàn)實世界的事物有屬性(人的身高,體重等)和行為(人可以學(xué)習(xí),吃飯等)
Java中用class描述事物也是如此,成員變量 就是事物的屬性,成員方法 就是事物的行為
定義類其實就是定義類的成員(成員變量和成員方法)
/**
事物:
屬性 事物的信息描述
行為 事物的功能
類:
成員變量 事物的屬性
成員方法 事物的行為
定義一個類,其實就是定義該類的成員變量和成員方法。
案例:我們來完成一個學(xué)生類的定義。
學(xué)生事物:
屬性:姓名,年齡,地址...
行為:學(xué)習(xí),吃飯,睡覺...
把事物要轉(zhuǎn)換為對應(yīng)的類:
學(xué)生類:
成員變量:姓名,年齡,地址...
成員方法:學(xué)習(xí),吃飯,睡覺...
成員變量:和以前變量的定義是一樣的格式,但是位置不同,在類中方法外。
成員方法:和以前的方法定義是一樣的格式,但是今天把static先去掉。
首先我們應(yīng)該定義一個類,然后完成類的成員。
*/
//這是我的學(xué)生類
class Student {
//定義變量
String name;//姓名
int age;//年齡
String address;//地址
//定義方法
//學(xué)習(xí)的方法
public void study() {
System.out.println("學(xué)生愛學(xué)習(xí)");
}
//吃飯的方法
public void eat() {
System.out.println("學(xué)習(xí)餓了,要吃飯");
}
//睡覺的方法
public void sleep() {
System.out.println("學(xué)習(xí)累了,要睡覺");
}
}
2.3 對象內(nèi)存圖
1個對象的內(nèi)存圖:一個對象的基本初始化過程
2個對象的內(nèi)存圖:方法的共用
3個對象的內(nèi)存圖:其中有兩個引用指向同一個對象
2.4 成員變量和局部變量的區(qū)別
注意事項:局部變量名稱可以和成員變量名稱一樣,在方法中使用的時候,采用的是就近原則。
class Varialbe {
//成員變量
//int num = 10;
int num; //0
public void show() {
//int num2 = 20; //局部變量
//可能尚未初始化變量num2
//int num2; //沒有默認值
int num2 = 20;
System.out.println(num2);
//int num = 100;
System.out.println(num);
}
}
class VariableDemo {
public static void main(String[] args) {
Varialbe v = new Varialbe();
System.out.println(v.num); //訪問成員變量
v.show();
}
}
2.5 形式參數(shù)問題
基本類型作為形式參數(shù):形式參數(shù)的改變不影響實際參數(shù)
引用類型作為形式參數(shù):形式參數(shù)的改變直接影響實際參數(shù)
/**
形式參數(shù)的問題:
基本類型:形式參數(shù)的改變不影響實際參數(shù)
引用類型:形式參數(shù)的改變直接影響實際參數(shù)
*/
//形式參數(shù)是基本類型
class Demo {
public int sum(int a,int b) {
return a + b;
}
}
//形式參數(shù)是引用類型
class Student {
public void show() {
System.out.println("我愛學(xué)習(xí)");
}
}
class StudentDemo {
//如果你看到了一個方法的形式參數(shù)是一個類類型(引用類型),這里其實需要的是該類的對象。
public void method(Student s) { //調(diào)用的時候,把main方法中的s的地址傳遞到了這里 Student s = new Student();
s.show();
}
}
class ArgsTest {
public static void main(String[] args) {
//形式參數(shù)是基本類型的調(diào)用
Demo d = new Demo();
int result = d.sum(10,20);
System.out.println("result:"+result);
System.out.println("--------------");
//形式參數(shù)是引用類型的調(diào)用
//需求:我要調(diào)用StudentDemo類中的method()方法
StudentDemo sd = new StudentDemo();
//創(chuàng)建學(xué)生對象
Student s = new Student();
sd.method(s); //把s的地址給到了這里
}
}
運行結(jié)果:
2.6 匿名對象
匿名對象:就是沒有名字的對象。是對象的一種簡化表示形式
匿名對象的兩種使用情況:對象調(diào)用方法僅僅一次的時候;作為實際參數(shù)傳遞。
/**
匿名對象:就是沒有名字的對象。
匿名對象的應(yīng)用場景:
A:調(diào)用方法,僅僅只調(diào)用一次的時候。
注意:調(diào)用多次的時候,不適合。
那么,這種匿名調(diào)用有什么好處嗎?
有,匿名對象調(diào)用完畢就是垃圾。可以被垃圾回收器回收。
B:匿名對象可以作為實際參數(shù)傳遞
*/
class Student {
public void show() {
System.out.println("我愛學(xué)習(xí)");
}
}
class StudentDemo {
public void method(Student s) {
s.show();
}
}
class NoNameDemo {
public static void main(String[] args) {
//帶名字的調(diào)用
Student s = new Student();
s.show();
s.show();
System.out.println("--------------");
//匿名對象
//new Student();
//匿名對象調(diào)用方法
new Student().show();
new Student().show(); //這里其實是重新創(chuàng)建了一個新的對象
System.out.println("--------------");
//匿名對象作為實際參數(shù)傳遞
StudentDemo sd = new StudentDemo();
//Student ss = new Student();
//sd.method(ss); //這里的s是一個實際參數(shù)
//匿名對象
sd.method(new Student());
//在來一個
new StudentDemo().method(new Student());
}
}
運行結(jié)果:
2.7 封裝(private)
封裝概述:是指隱藏對象的屬性和實現(xiàn)細節(jié),僅對外提供公共訪問方式。
封裝的好處:
- 隱藏實現(xiàn)細節(jié),提供公共的訪問方式
- 提高了代碼的復(fù)用性
- 提高安全性。
封裝原則:
- 將不需要對外提供的內(nèi)容都隱藏起來。
- 把屬性隱藏,提供公共方法對其訪問。
private關(guān)鍵字:
- 是一個權(quán)限修飾符。
- 可以修飾成員(成員變量和成員方法)
- 被private修飾的成員只在本類中才能訪問。
private最常見的應(yīng)用:
- 把成員變量用private修飾
- 提供對應(yīng)的getXxx()/setXxx()方法
- 一個標(biāo)準(zhǔn)的案例的使用
/**
封裝和private的應(yīng)用:
A:把成員變量用private修飾
B:提高對應(yīng)的getXxx()和setXxx()方法
*/
//定義學(xué)生類
class Student {
//姓名
private String name;
//年齡
private int age;
//姓名獲取值
public String getName() {
return name;
}
//姓名設(shè)置值
public void setName(String n) {
name = n;
}
//年齡獲取值
public int getAge() {
return age;
}
//年齡賦值
public void setAge(int a) {
age = a;
}
}
//測試類
class StudentTest {
public static void main(String[] args) {
//創(chuàng)建學(xué)生對象
Student s = new Student();
//使用成員變量
//錯誤:被私有修飾了,外界不能直接訪問了
//System.out.println(s.name+"---"+s.age);
System.out.println(s.getName()+"---"+s.getAge());
//給成員變量賦值
//s.name = "林青霞";
//s.age = 27;
//通過方法給賦值
s.setName("林青霞");
s.setAge(27);
System.out.println(s.getName()+"---"+s.getAge());
}
}
運行結(jié)果:
2.8 this關(guān)鍵字
this:代表所在類的對象引用
記?。悍椒ū荒膫€對象調(diào)用,this就代表那個對象
什么時候使用this呢?
- 局部變量隱藏成員變量
- 其他用法后面和super一起講解
/**
我們曾經(jīng)曰:起名字要做到見名知意。
this:是當(dāng)前類的對象引用。簡單的記,它就代表當(dāng)前類的一個對象。
注意:誰調(diào)用這個方法,在該方法內(nèi)部的this就代表誰。
this的場景:
解決局部變量隱藏成員變量
this:哪個對象調(diào)用那個方法,this就代表那個對象
*/
class Student {
private String name;
private int age;
public String getName() {
return name; //這里其實是隱含了this
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
class StudentTest2 {
public static void main(String[] args) {
//創(chuàng)建一個對象
Student s1 = new Student();
s1.setName("林青霞");
s1.setAge(27);
System.out.println(s1.getName()+"---"+s1.getAge());
//創(chuàng)建第二個對象
Student s2 = new Student();
s2.setName("劉意");
s2.setAge(30);
System.out.println(s2.getName()+"---"+s2.getAge());
}
}
運行結(jié)果:
this關(guān)鍵字的內(nèi)存圖解:
2.9 構(gòu)造方法
構(gòu)造方法作用概述:給對象的數(shù)據(jù)進行初始化
構(gòu)造方法格式
- 方法名與類名相同
- 沒有返回值類型,連void都沒有
- 沒有具體的返回值
構(gòu)造方法注意事項
- 如果你不提供構(gòu)造方法,系統(tǒng)會給出默認構(gòu)造方法
- 如果你提供了構(gòu)造方法,系統(tǒng)將不再提供
- 構(gòu)造方法也是可以重載的
給成員變量賦值有兩種方式:
- setXxx()
- 構(gòu)造方法
PS:
1、一般函數(shù)和構(gòu)造函數(shù)什么區(qū)別呢?
構(gòu)造函數(shù):對象創(chuàng)建時,就會調(diào)用與之對應(yīng)的構(gòu)造函數(shù),對對象進行初始化。
一般函數(shù):對象創(chuàng)建后,需要函數(shù)功能時才調(diào)用。
構(gòu)造函數(shù):對象創(chuàng)建時,會調(diào)用并且只調(diào)用一次。
一般函數(shù):對象創(chuàng)建后,可以被調(diào)用多次。
2、創(chuàng)建對象都必須要通過構(gòu)造函數(shù)初始化。
一個類中如果沒有定義過構(gòu)造函數(shù),那么該類中會有一個默認的空參數(shù)構(gòu)造函數(shù)。
如果在類中定義了指定的構(gòu)造函數(shù),那么類中的默認構(gòu)造函數(shù)就沒有了。
3、多個構(gòu)造函數(shù)是以重載的形式存在的。
/**
我們一直在使用構(gòu)造方法,但是,我們確沒有定義構(gòu)造方法,用的是哪里來的呢?
構(gòu)造方法的注意事項:
A:如果我們沒有給出構(gòu)造方法,系統(tǒng)將自動提供一個無參構(gòu)造方法。
B:如果我們給出了構(gòu)造方法,系統(tǒng)將不再提供默認的無參構(gòu)造方法。
注意:這個時候,如果我們還想使用無參構(gòu)造方法,就必須自己給出。建議永遠自己給出無參構(gòu)造方法
給成員變量賦值有兩種方式:
A:setXxx()
B:構(gòu)造方法
*/
class Student {
private String name;
private int age;
public Student() {
//System.out.println("我給了,你還給不");
System.out.println("這是無參構(gòu)造方法");
}
//構(gòu)造方法的重載格式
public Student(String name) {
System.out.println("這是帶一個String類型的構(gòu)造方法");
this.name = name;
}
public Student(int age) {
System.out.println("這是帶一個int類型的構(gòu)造方法");
this.age = age;
}
public Student(String name,int age) {
System.out.println("這是一個帶多個參數(shù)的構(gòu)造方法");
this.name = name;
this.age = age;
}
public void show() {
System.out.println(name+"---"+age);
}
}
class ConstructDemo2 {
public static void main(String[] args) {
//創(chuàng)建對象
Student s = new Student();
s.show();
System.out.println("-------------");
//創(chuàng)建對象2
Student s2 = new Student("林青霞");
s2.show();
System.out.println("-------------");
//創(chuàng)建對象3
Student s3 = new Student(27);
s3.show();
System.out.println("-------------");
//創(chuàng)建對象4
Student s4 = new Student("林青霞",27);
s4.show();
}
}
2.10 類的成員方法
成員方法其實就是我們前面講過的方法
方法具體劃分:
- 根據(jù)返回值:有明確返回值方法;返回void類型的方法
- 根據(jù)形式參數(shù):無參方法;帶參方法
一個基本類的標(biāo)準(zhǔn)代碼寫法
/**
一個標(biāo)準(zhǔn)代碼的最終版。
學(xué)生類:
成員變量:
name,age
構(gòu)造方法:
無參,帶兩個參
成員方法:
getXxx()/setXxx()
show():輸出該類的所有成員變量值
給成員變量賦值:
A:setXxx()方法
B:構(gòu)造方法
輸出成員變量值的方式:
A:通過getXxx()分別獲取然后拼接
B:通過調(diào)用show()方法搞定
*/
class Student {
//姓名
private String name;
//年齡
private int age;
//構(gòu)造方法
public Student() {
}
public Student(String name,int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
//輸出所有的成員變量值
public void show() {
System.out.println(name+"---"+age);
}
}
//測試類
class StudentTest {
public static void main(String[] args) {
//方式1給成員變量賦值
//無參構(gòu)造+setXxx()
Student s1 = new Student();
s1.setName("林青霞");
s1.setAge(27);
//輸出值
System.out.println(s1.getName()+"---"+s1.getAge());
s1.show();
System.out.println("----------------------------");
//方式2給成員變量賦值
Student s2 = new Student("劉意",30);
System.out.println(s2.getName()+"---"+s2.getAge());
s2.show();
}
}
運行結(jié)果:
2.11 類的初始化過程
Student s = new Student();在內(nèi)存中做了哪些事情?
- 加載Student.class文件進內(nèi)存
- 在棧內(nèi)存為s開辟空間
- 在堆內(nèi)存為學(xué)生對象開辟空間
- 對學(xué)生對象的成員變量進行默認初始化
- 對學(xué)生對象的成員變量進行顯示初始化
- 通過構(gòu)造方法對學(xué)生對象的成員變量賦值
- 學(xué)生對象初始化完畢,把對象地址賦值給s變量
2.12 static關(guān)鍵字
static關(guān)鍵字可以修飾成員變量和成員方法
static關(guān)鍵字特點
- 隨著類的加載而加載
- 優(yōu)先于對象存在
- 被類的所有對象共享
- 這也是我們判斷是否使用靜態(tài)關(guān)鍵字的條件
- 可以通過類名調(diào)用
static關(guān)鍵字注意事項
- 在靜態(tài)方法中是沒有this關(guān)鍵字的
- 靜態(tài)方法只能訪問靜態(tài)的成員變量和靜態(tài)的成員方法
靜態(tài)的內(nèi)存圖
靜態(tài)變量和成員變量的區(qū)別
2.13 main方法是靜態(tài)的
public static void main(String[] args) {}
- public 被jvm調(diào)用,訪問權(quán)限足夠大。
- static 被jvm調(diào)用,不用創(chuàng)建對象,直接類名訪問
- void被jvm調(diào)用,不需要給jvm返回值
- main 一個通用的名稱,雖然不是關(guān)鍵字,但是被jvm識別
- String[] args 以前用于接收鍵盤錄入的
- 靜態(tài)什么時候用?
靜態(tài)變量
當(dāng)分析對象中所具備的成員變量的值都是相同時,這時這個成員就可以被靜態(tài)修飾。
只要數(shù)據(jù)在對象中都是不同的,就是對象的特有數(shù)據(jù),必須存儲在對象中,是非靜態(tài)的。
如果是相同的數(shù)據(jù),對象不需要做修改,只需要使用即可,不需要存儲在對象中,定義成靜態(tài)的。
靜態(tài)函數(shù)
函數(shù)是否用靜態(tài)修飾,就參考一點,就是該函數(shù)功能是否需要訪問到對象中的特有數(shù)據(jù)。
簡單點說,從源代碼看,該功能是否需要訪問非靜態(tài)的成員變量,如果需要,該功能就是非靜態(tài)的。
如果不需要,就可以將該功能定義成靜態(tài)的。當(dāng)然,也可以定義成非靜態(tài),但是非靜態(tài)需要被對象調(diào)用。
如果沒有訪問特有數(shù)據(jù)的方法,該對象的創(chuàng)建是沒有意義。
/*
main方法的格式講解:
public static void main(String[] args) {...}
public:公共的,訪問權(quán)限是最大的。由于main方法是被jvm調(diào)用,所以權(quán)限要夠大。
static:靜態(tài)的,不需要創(chuàng)建對象,通過類名就可以。方便jvm的調(diào)用。
void:因為我們曾經(jīng)說過,方法的返回值是返回給調(diào)用者,而main方法是被jvm調(diào)用。你返回內(nèi)容給jvm沒有意義。
main:是一個常見的方法入口。我見過的語言都是以main作為入口。
String[] args:這是一個字符串?dāng)?shù)組。值去哪里了?
這個東西到底有什么用啊?怎么給值啊?
這個東西早期是為了接收鍵盤錄入的數(shù)據(jù)的。
格式是:
java MainDemo hello world java
*/
class MainDemo {
public static void main(String[] args) {
//System.out.println(args); //[Ljava.lang.String;@175078b
//System.out.println(args.length); //0
//System.out.println(args[0]); //ArrayIndexOutOfBoundsException
//接收數(shù)據(jù)后
System.out.println(args);
System.out.println(args.length);
//System.out.println(args[0]);
for(int x=0; x<args.length; x++) {
System.out.println(args[x]);
}
}
}
運行結(jié)果: