Java基礎第七天
面向對象思想
類與對象及其使用
對象的內存圖
成員變量和局部變量的區別
匿名對象
封裝(private)
this關鍵字
構造方法
static關鍵字
面向對象思想引入
前面我們講過數組,當有多個數組都需要遍歷時,我們可以將遍歷的代碼封裝到方法中,需要遍歷時,就調用相應的方法即可,提高代碼的複用性。在對數組遍歷的基礎上繼續增加需求,比如獲取最值,數值逆序等,同樣需要將這些功能封裝到相應的方法中。這樣繼續封裝會發現方法越來越多,於是就想能不能將這些方法繼續進行封裝呢?通過前面的講解我們知道類是可以存放方法的,所以,我們就考慮使用類封裝來這多個方法,將來再做數組的操作時,不用去找具體的方法,先找到這個類,然後使用這個類中的方法。這就是面向對象思想的編程方式。
面向過程思想概述
我們來回想一下,這幾天我們完成一個需求的步驟:首先是搞清楚我們要做什麼,然後在分析怎麼做,最後我們再代碼體現。一步一步去實現,而具體的每一步都需要我們去實現和操作。這些步驟相互調用和協作,完成我們的需求。
在上面的每一個具體步驟中我們都是參與者,並且需要面對具體的每一個步驟和過程,這就是面向過程最直接的體現。
那麼什麼是面向過程開發呢? 面向過程開發,其實就是面向着具體的每一個步驟和過程,把每一個步驟和過程完成,然後由這些功能方法相互調用,完成需求。
面向過程的代表語言:C語言
面向對象思想概述
當需求單一,或者簡單時,我們一步一步去操作沒問題,並且效率也挺高。可隨着需求的更改,功能的增多,發現需要面對每一個步驟很麻煩了,這時就開始思索,能不能把這些步驟和功能在進行封裝,封裝時根據不同的功能,進行不同的封裝,功能類似的封裝在一起。這樣結構就清晰了很多。用的時候,找到對應的類就可以了。這就是面向對象的思想。接下來我們看看面向對象到底是什麼?
1:面向對象思想
面向對象是基於面向過程的編程思想。
面向過程:強調的是每一個功能的步驟
面向對象:強調的是對象,然後由對象去調用功能
2:面向對象的思想特點
A:是一種更符合我們思想習慣的思想
B:可以將複雜的事情簡單化
C:將我們從執行者變成了指揮者
舉例:
買電腦:
面向過程:我的瞭解電腦--瞭解我自己的需求--找對應的參數信息--去中關村買電腦--討價還價--買回電腦
面向對象:我知道我要買電腦 -- 班長去給我買 -- 班長就買回來了
洗衣服:
面向過程:把衣服脫下--找一個盆--放點洗衣粉--加點水--把衣服扔進去--搓一搓--清洗衣服--擰乾--晾起來
面向對象:把衣服脫下--打開全自動洗衣機--扔進去--一鍵即可--晾起來
吃飯:
面向過程:去超市買菜--摘菜--洗菜--切菜--炒菜--盛起來--吃
面向對象:上飯店吃飯,你--服務員(點菜)--廚師(做菜)--服務員(端菜)--吃
家常事物,買洗衣機和去飯店太不划算了,所以,找個對象。
萬事萬物皆對象
面向過程思想和麪向對象思想的代碼舉例
把大象裝進冰箱
面向過程:
動作有哪些呢?
A:打開冰箱門
B:裝進大象
C:關閉冰箱門
代碼體現;
class Demo {
public static void main(String[] args) {
/*
System.out.println("打開冰箱門");
//打開冰箱門的東西,我現在僅僅是爲了演示,就寫了一個輸出語句
//其實,它可能需要做很多操作。
//這個時候代碼就比較多一些了
//假設我要多次打開冰箱門,
//代碼一多,每次都寫一遍,麻煩不
//我們就應該用方法改進
System.out.println("裝進大象");
System.out.println("關閉冰箱門");
*/
//寫了方法以後,調用就改變了
open();
in();
close();
}
public static void open() {
System.out.println("打開冰箱門");
}
public static void in() {
System.out.println("裝進大象");
}
public static void close() {
System.out.println("關閉冰箱門");
}
}
面向對象:
我們怎麼才能更符合面向對象思想呢?
A:有哪些類呢?
B:每個類有哪些東西呢?
C:類與類直接的關係是什麼呢?
把大象裝進冰箱的分析? (如何分析有哪些類呢?UML。名詞提取法。)
A:有哪些類呢?
大象
冰箱
Demo
B:每個類有哪些東西呢?
大象:
進去
冰箱:
開門
關門
Demo:
main方法
C:類與類直接的關係是什麼呢?
Demo中使用大象和冰箱類的功能。
代碼體現:
class 大象 {
public static void in() {
System.out.println("裝進大象");
}
}
class 冰箱 {
public static void open() {
System.out.println("打開冰箱門");
}
public static void close() {
System.out.println("關閉冰箱門");
}
}
class Demo {
public static void main(String[] args) {
冰箱調用開門
大象調用進去
冰箱調用關門
}
}
面向對象開發,設計,特徵
面向對象開發
就是不斷的創建對象,使用對象,指揮對象做事情
面向對象設計
其實就是在管理和維護對象之間的關係。
面向對象特徵
封裝(encapsulation)
繼承(inheritance)
多態(polymorphism)
類與對象關係
我們學習編程語言,就是爲了模擬現實世界的事物,實現信息化。比如:去超市買東西的計費系統,去銀行辦業務的系統。
我們如何表示一個現實世界事物呢:
屬性 就是該事物的描述信息
行爲 就是該事物能夠做什麼
舉例:學生事物
現實世界中是如何描述一個事物的呢?
舉例:學生
姓名,年齡,性別...
學習,吃飯,睡覺
屬性:該事物的描述信息
行爲:該事物能夠做什麼
我們學習編程語言,是爲了模擬現實世界的事物的。
而我們學習的編程語言Java中最基本的單位是:類。
所以,我們就應該把事物通過類來體現出來:
由此,我們就得到了現實世界事物和類的對應關係:
事物:類:
屬性成員變量
行爲成員方法
類:是一組相關的屬性和行爲的集合。是一個抽象的概念。
對象:是該類事物的具體表現形式。具體存在的個體。
舉例:
學生:類
班長:對象
類與對象的關係如圖
類的定義
現實世界的事物
屬性人的身高,體重等
行爲人可以學習,吃飯等
Java中用class描述事物也是如此
成員變量就是事物的屬性
成員方法就是事物的行爲
定義類其實就是定義類的成員(成員變量和成員方法)
/*
事物:
屬性事物的信息描述
行爲事物的功能
類:
成員變量事物的屬性
成員方法事物的行爲
定義一個類,其實就是定義該類的成員變量和成員方法。
案例:我們來完成一個學生類的定義。
學生事物:
屬性:姓名,年齡,地址...
行爲:學習,吃飯,睡覺...
把事物要轉換爲對應的類:
學生類:
成員變量:姓名,年齡,地址...
成員方法:學習,吃飯,睡覺...
成員變量:和以前變量的定義是一樣的格式,但是位置不同,在類中方法外。
成員方法:和以前的方法定義是一樣的格式,但是今天把static先去掉。
首先我們應該定義一個類,然後完成類的成員。
*/
class Student { //定義變量(成員變量) String name; //性別 男1 女0 int sex; //年齡 int age; //地址 String address; //學習的方法 public void study() { System.out.println("學生愛學習"); } //睡覺的方法 public void sleep() { System.out.println("學習累了要睡覺"); } //吃飯的方法 public void eat() { System.out.println("學習餓了,要吃飯"); } }
/*
手機事物:
屬性:品牌,價格,顏色...
行爲:打電話,發短信,玩遊戲...
手機類:
成員變量:品牌,價格,顏色
成員方法:打電話,發短信,玩遊戲
*/
class Phone { //變量(成員變量) //品牌 String brand; //價格 int price; //顏色 String color; //打電話的方法 public void call(String name) { System.out.println("給"+name+"打電話"); } //發短信的方法 public void send(String name) { System.out.println("給"+name+"發短信"); } //玩遊戲的方法 public void game() { System.out.println("玩遊戲"); } }
學生類(講解)
如何定義
按照事物到類的過程一步步分析
如何使用
創建對象:
類名 對象名 = new 類名();
對象名.成員變量
對象名.成員方法
/*
在一個java文件中寫兩個類:一個基本的類,一個測試類。
注意:文件名稱和測試類名稱一致。
如何使用呢?
創建對象使用。
如何創建對象呢?
格式:類名 對象名 = new 類名();
如何使用成員變量呢?
對象名.變量名
如何使用成員方法呢?
對象名.方法名(...)
*/
class Student { //定義變量(成員變量) String name; //性別 男1 女0 int sex; //年齡 int age; //地址 String address; //學習的方法 public void study() { System.out.println("學生愛學習"); } //睡覺的方法 public void sleep() { System.out.println("學習累了要睡覺"); } //吃飯的方法 public void eat() { System.out.println("學習餓了,要吃飯"); } } class StudentDemo { public static void main(String[] args) { //創建對象:類名 對象名 = new 類名(); Student banzhang = new Student(); //調用:對象名.成員變量 // 對象名.成員方法 System.out.println(banzhang.name); System.out.println(banzhang.age); System.out.println(banzhang.address); banzhang.study(); banzhang.sleep(); banzhang.eat(); Student s = new Student();//?創建對象 } }
/* 手機類的測試 */ class Phone { String brand; int price; String color; public void call(String name,int num) { System.out.println("給"+name+"打電話"+num); } public void send(String name) { System.out.println("給"+name+"發短信"); } public void game() { System.out.println("打遊戲"); } } class PhoneDemo { public static void main(String[] args) { Phone iPhone = new Phone(); System.out.println(iPhone.brand); System.out.println(iPhone.price); System.out.println(iPhone.color); iPhone.game(); iPhone.call("家裏",1283083); iPhone.send("家裏"); } }
1個對象的內存圖
一個對象的基本初始化過程
2個對象的內存圖
3個對象的內存圖
其中有兩個引用指向同一個對象
成員變量和局部變量的區別
在類中的位置不同
成員變量 類中方法外
局部變量 方法內或者方法聲明上
在內存中的位置不同
成員變量 堆內存
局部變量 棧內
生命週期不同
成員變量 隨着對象的存在而存在,隨着對象的消失而消失
局部變量 隨着方法的調用而存在,隨着方法的調用完畢而消失
初始化值不同
成員變量 有默認的初始化值
局部變量 沒有默認的初始化值,必須先定義,賦值,才能使用。
/*
成員變量和局部變量的區別?
A:在類中的位置不同
成員變量:在類中方法外
局部變量:在方法定義中或者方法聲明上
B:在內存中的位置不同
成員變量:在堆內存
局部變量:在棧內存
C:生命週期不同
成員變量:隨着對象的創建而存在,隨着對象的消失而消失
局部變量:隨着方法的調用而存在,隨着方法的調用完畢而消失
D:初始化值不同
成員變量:有默認初始化值
局部變量:沒有默認初始化值,必須定義,賦值,然後才能使用。
注意事項:
局部變量名稱可以和成員變量名稱一樣,在方法中使用的時候,採用的是就近原則。
*/
class Varialbe { int a ;//成員變量 public void show(){ //錯誤: 可能尚未初始化變量i //int i ; int i = 0 ;//局部變量 System.out.println(i); } } class VariableDemo { public static void main(String[] args){ Varialbe v = new Varialbe(); v.show(); System.out.println(v.a); } }
形式參數問題
基本類型作爲形式參數
引用類型作爲形式參數
/*
形式參數的問題:
基本類型:形式參數的改變不影響實際參數
引用類型:形式參數的改變直接影響實際參數
*/
class ZhengShuJiSuan { public void sum(int a,int b) { int c = a + b; System.out.println(c); } } class ShuZuJiSuan { public void printArr(int[] arr) { int length = arr.length; System.out.println("length="+length); } } class LeiJiSuan { public void printMethod(Student student) { student.study(); student.eat(); } } class Student { public void study() { System.out.println("我要好好學習"); } public void eat() { System.out.println("我要好好吃飯"); } } class TestXingCan { public static void main(String[] args) { ZhengShuJiSuan zsjs = new ZhengShuJiSuan(); zsjs.sum(3,5); ShuZuJiSuan szjs = new ShuZuJiSuan(); int[] array = new int[5]; szjs.printArr(array); LeiJiSuan ljs = new LeiJiSuan(); Student student = new Student(); ljs.printMethod(student); System.out.println("Hello World!"); } }
匿名對象
匿名對象:就是沒有名字的對象。【面試】
是對象的一種簡化表示形式
匿名對象的兩種使用情況
對象調用方法僅僅一次的時候
作爲實際參數傳遞
/*
匿名對象:就是沒有名字的對象。
匿名對象的應用場景:
A:調用方法,僅僅只調用一次的時候。
注意:調用多次的時候,不適合。
那麼,這種匿名調用有什麼好處嗎?
有,匿名對象調用完畢就是垃圾。可以被垃圾回收器回收。
B:匿名對象可以作爲實際參數傳遞
*/
class Student { public void show() { System.out.println("我愛學習"); } } class LeiMethod { public void print(Student s) { s.show(); } } class NoNameDemo { public static void main(String[] args) { Student student = new Student(); student.show();//第一個 new Student().show();//第二個 new LeiMethod().print(new Student());//第三個 //Student student = new Student(); new LeiMethod.print(new Student()); //System.out.println("Hello World!"); } }
封裝概述
封裝概述
是指隱藏對象的屬性和實現細節,僅對外提供公共訪問方式。
好處:
隱藏實現細節,提供公共的訪問方式
提高了代碼的複用性
提高安全性。
封裝原則:
將不需要對外提供的內容都隱藏起來。
把屬性隱藏,提供公共方法對其訪問。
/*
定義一個學生類:
成員變量:name,age
成員方法:show()方法
我們在使用這個案例的過程中,發現了一個問題:
通過對象去給成員變量賦值,可以賦值一些非法的數據。
這是不合理的。
應該是這個樣子的:在賦值之前,先對數據進行判斷。
判斷到底在哪裏做比較合適呢?
StudentDemo類是一個測試類,測試類一般只創建對象,調用方法。
所以,這個判斷應該定義在Student類中。
而我們在成員變量的位置可不可以進行數據判斷呢?
是不可以的,因爲做數據校驗,必須要依靠一些邏輯語句。
邏輯語句是應該定義在方法中的,所以,我們最終決定在Student類中提供一個方法
來對數據進行校驗。
按照我們前面的分析,我們給出了一個方法進行校驗。
但是呢,它偏偏不調用方法來賦值,還是直接賦值了,
這樣我們的方法就沒有起到作用。
我就應該要求你必須使用我的方法,而不能直接調用成員變量賦值。
怎麼去強制要求不能直接使用成員變量呢?
針對這種情況,Java就提供了一個關鍵字 private
private:私有的。可以修飾成員變量和成員方法。
注意:被private修飾的成員只能在本類中訪問。
其實我講到現在講解的是一個封裝的思想。
封裝:是指隱藏對象的屬性和實現細節,僅對外提供公共訪問方式。
*/
private關鍵字
private關鍵字:
是一個權限修飾符。
可以修飾成員(成員變量和成員方法)
被private修飾的成員只在本類中才能訪問。
private最常見的應用:
把成員變量用private修飾
提供對應的getXxx()/setXxx()方法
一個標準的案例的使用
/*
private:
是一個權限修飾符
可以修飾成員變量和成員方法
被其修飾的成員只能在本類中被訪問
*/
class Demo { private int num = 10; public int getNum() { return num; } public void setNum(int a) { if(a < 0 || a > 100){ System.out.println("我是有底線的"); }else{ num = a; } } private void study() { System.out.println("我要學習"); } public void method() { study(); } } class PrivateDemo { public static void main(String[] args) { Demo demo = new Demo(); demo.setNum(120); System.out.println(demo.getNum()); demo.method(); } }
正常Student類測試
/*
封裝和private的應用:
A:把成員變量用private修飾
B:提高對應的getXxx()和setXxx()方法
*/
//定義學生類 class Student { //姓名 private String name; //年齡 private int age; //姓名獲取值 public String getName() { return name; } //姓名設置值 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) { //創建學生對象 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()); } }
This使用
this:代表所在類的對象引用
記住:
方法被哪個對象調用,this就代表那個對象
什麼時候使用this呢?
局部變量隱藏成員變量
其他用法後面和super一起講解
案例:
/*
我們曾經曰:起名字要做到見名知意。
this:是當前類的對象引用。簡單的記,它就代表當前類的一個對象。
注意:誰調用這個方法,在該方法內部的this就代表誰。
this的場景:
解決局部變量隱藏成員變量
*/
class Student { private String name; private String address; private int age; /** 構造方法 */ public Student() { } public Student(String name) { this.name = name; } public Student(String name,int age) { this.name = name; this.age = age; } /** 成員方法,獲取name值 */ public String getName() { return name; } } class ConstructDemo { public static void main(String[] args) { Student student = new Student("林青霞"); System.out.println(student.getName()); Student student1 = new Student("林青霞",18); System.out.println(student1.getName()); } }
構造方法
構造方法作用概述
給對象的數據進行初始化
構造方法格式
方法名與類名相同
沒有返回值類型,連void都沒有
沒有具體的返回值
構造方法注意事項
如果你不提供構造方法,系統會給出默認構造方法
如果你提供了構造方法,系統將不再提供
構造方法也是可以重載的
/*
構造方法:
給對象的數據進行初始化
格式:
A:方法名與類名相同
B:沒有返回值類型,連void都沒有
C:沒有具體的返回值
*/
方法構造二
/*
我們一直在使用構造方法,但是,我們確沒有定義構造方法,用的是哪裏來的呢?
構造方法的注意事項:
A:如果我們沒有給出構造方法,系統將自動提供一個無參構造方法。
B:如果我們給出了構造方法,系統將不再提供默認的無參構造方法。
注意:這個時候,如果我們還想使用無參構造方法,就必須自己給出。建議永遠自己給出無參構造方法
給成員變量賦值有兩種方式:
A:setXxx()
B:構造方法
*/
類的成員方法
成員方法其實就是我們前面講過的方法
方法具體劃分:
根據返回值
有明確返回值方法
返回void類型的方法
根據形式參數
無參方法
帶參方法
案例:
/*
類的組成:成員變量,成員方法
今天我們又加入了一個新的成員:構造方法。
以後再提類的組成:
成員變量
構造方法
成員方法
根據返回值:
void類型
非void類型
形式參數:
空參方法
非空參方法
*/
class Student { public String getString() { return "helloworld"; } public void show() { System.out.println("show"); } public void method(String name) { System.out.println(name); } public String function(String s1,String s2) { return s1+s2; } } class StudentDemo { public static void main(String[] args) { //創建對象 Student s = new Student(); //調用無參無返回值方法 s.show(); //調用無參有返回值方法 String result = s.getString(); System.out.println(result); //調用帶參無返回值的方法 s.method("林青霞"); //調用帶參帶返回值的方法 String result2 = s.function("hello","world"); System.out.println(result2); } }
一個基本類的標準代碼寫法
類
成員變量
構造方法
無參構造方法
帶參構造方法
成員方法
getXxx()
setXxx()
給成員變量賦值的方式
無參構造方法+setXxx()
帶參構造方法
一個標準學生代碼以及測試:
/*
一個標準代碼的最終版。
學生類:
成員變量:
name,age
構造方法:
無參,帶兩個參
成員方法:
getXxx()/setXxx()
show():輸出該類的所有成員變量值
給成員變量賦值:
A:setXxx()方法
B:構造方法
輸出成員變量值的方式:
A:通過getXxx()分別獲取然後拼接
B:通過調用show()方法搞定
*/
class Student { //姓名 private String name; //年齡 private int age; //構造方法 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給成員變量賦值 //無參構造+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(); } }