多個(gè)對(duì)象的內(nèi)存圖
/*
* Person類 : 描述了人這類事務(wù)的,不具體描述,抽象描述
* 描述人應(yīng)該具有什么,但是不詳細(xì)
*
* 屬性: 變量 人的性別和年齡 成員變量
* 行為: 方法 人吃飯,睡覺(jué)行為 成員方法
*
* 屬性和行為 : 類的成員 (組成類的一員)
*/
public class Person {
//人的姓名
String name ;
//人的年齡
int age;
//人的吃飯行為方法
public void eat() {
System.out.println("人在吃飯" + name +".."+age);
}
//人的睡覺(jué)行為
public void sleep() {
System.out.println("人在睡覺(jué)" + name +".."+age);
}
}
public static void main(String[] args) {
Person p1 = new Person();
Person p2 = new Person();
p1.name = "張三";
p1.age = 20;
p2.name = "李四";
p2.age = 22;
p1.eat();
p1.sleep();
p2.eat();
p2.sleep();
}
封裝
面向?qū)ο蟮某绦蛟O(shè)計(jì)中(oop),包含三大特征. 我們以后開(kāi)發(fā)程序,必須要體現(xiàn)出面向?qū)ο蟮娜筇卣?沒(méi)有體現(xiàn)出現(xiàn)三大特征,不是在用面向?qū)ο笏枷腴_(kāi)發(fā)程序.
- 封裝 (encapsulation)
- 繼承 (extends)
- 多態(tài) (polymorphic)
封裝概念
- 封裝的定義 : 隱藏具體的實(shí)現(xiàn)細(xì)節(jié),對(duì)外暴露使用方式.
- 現(xiàn)實(shí)中的封裝實(shí)例 , 筆記本就是例子, 硬件看不到,有什么不知道. 鍵盤(pán),鼠標(biāo)可以操作
封裝的好處
- 提升安全性
- 提高程序的復(fù)用性
- 提高程序的可擴(kuò)展
封裝的實(shí)現(xiàn)
- 修飾符,也是權(quán)限修飾符 private (私有的)
- private成員修飾符,不能寫(xiě)在方法里面
- 被private修飾的成員,訪問(wèn)權(quán)限是最低的
- 私有修飾的成員,只能在本類使用,出去定義的類,就無(wú)效
- private私有的修飾,只是封裝的一種體現(xiàn)形式,不能完全代表封裝
提高公共的訪問(wèn)方式
- 方法的形式出現(xiàn),定義公共方法,讓外界訪問(wèn)私有修飾的成員
- 方法:對(duì)類的成員變量,賦值或者是取值操作
- 賦值方法名 : set開(kāi)頭
- 取值方法名 : get開(kāi)頭
/*
* setAge方法,對(duì)成員變量age賦值
* 值不一定是什么,方法傳遞參數(shù)
*/
public void setAge(int a) {
//a的值判斷
if(a < 0 || a > 120) {
//自己定義值
age = 0;
}else {
age = a;
}
}
//定義方法.獲取age值
public int getAge() {
return age;
}
標(biāo)準(zhǔn)的Person對(duì)象,私有修飾寫(xiě)法(一)
public class Person {
private String name;
private int age ;
/*
* name成員變量的get/set方法
* set方法是賦值的,方法傳遞參數(shù)
* get方法是獲取值,無(wú)參數(shù),有返回值
*/
public void setName(String n) {
name = n;
}
public String getName() {
return name;
}
/*
* age成員變量的get/set方法
* set方法是賦值的,方法傳遞參數(shù)
* get方法是獲取值,無(wú)參數(shù),有返回值
*/
public void setAge(int a) {
age = a;
}
public int getAge() {
return age;
}
}
public static void main(String[] args) {
//創(chuàng)建Person類對(duì)象,調(diào)用方法get/set ,賦值和取值操作
Person p = new Person();
p.setName("張三");
p.setAge(20);
System.out.println( p.getAge() );
System.out.println( p.getName() );
}
方法的變量和類的成員變量同名
方法中的變量 (方法體定義的,和參數(shù)中定義),只屬于這個(gè)方法,不屬于其他的任何成員
方法中沒(méi)有定義的變量,使用變量,找成員位置變量
public class Person {
private String name;
private int age = 1;
/*
* setAge(int a) 閱讀性, 變量a不好理解
* 見(jiàn)名知意
*/
public void setAge(int age) {
age = age;
}
public int getAge() {
return age;
}
}
public static void main(String[] args) {
//創(chuàng)建Person類對(duì)象,調(diào)用方法get/set ,賦值和取值操作
Person p = new Person();
p.setAge(20);
System.out.println( p.getAge());
}
this關(guān)鍵字
this翻譯為這個(gè),這里.
this程序中的含義 : this表示當(dāng)前對(duì)象的引用 (this本質(zhì)上理解為就是一個(gè)對(duì)象)
this理解為 : 哪個(gè)對(duì)象調(diào)用的,this就表示哪個(gè)對(duì)象
-
this用法 : this用于區(qū)分成員變量和局部變量的同名問(wèn)題
- this.變量名 : 表示類中的成員變量
- 變量名 : 表示方法的具備變量
public class Person {
private String name;
private int age = 1;
/*
* setAge(int a) 閱讀性, 變量a不好理解
* 見(jiàn)名知意
* 區(qū)分出,哪個(gè)age是方法局部的,哪個(gè)age是類的成員的
* this關(guān)鍵字區(qū)分
*/
public void setAge(int age) {
this.age = age;
}
public int getAge() {
return age;
}
}
成員變量和局部變量區(qū)別
- 變量的定義上區(qū)別
- 局部變量定義在方法內(nèi)部,方法參數(shù)
- 成員變量定義在方法外部,類的里面
- 變量的作用域上區(qū)別
- 局部變量作用在方法內(nèi)部,作用在定義的一對(duì){}里面
- 成員變量作用于整個(gè)的類中
- 變量的內(nèi)存位置
- 局部變量,跟隨的方法,進(jìn)入方法棧
- 成員變量,跟隨對(duì)象進(jìn)入到堆內(nèi)存
- 變量的生命周期不同
- 局部變量,跟隨方法出棧,銷毀,相對(duì)較短
- 成員變量,跟隨對(duì)象進(jìn)入到堆內(nèi)存,等待JVM進(jìn)行垃圾回收, 相對(duì)較長(zhǎng)
- 變量的初始化值不同
- 局部變量,不賦值不能使用,沒(méi)有默認(rèn)值
- 成員變量,在堆內(nèi)存,具有默認(rèn)值的
標(biāo)準(zhǔn)的Person對(duì)象的寫(xiě)法(二)
/*
* Person類中,定義姓名和年齡成員
* 要求類的成員變量,私有的修飾
* 并提供get / set 使用
*
* 標(biāo)準(zhǔn)的寫(xiě)法,以后就這樣寫(xiě)
*/
public class Person {
private String name;
private int age;
/*
* 成員變量,提供get/set方法
*/
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setAge(int age) {
this.age = age;
}
public int getAge() {
return age;
}
}
public static void main(String[] args) {
//創(chuàng)建Person類對(duì)象,調(diào)用方法get/set ,賦值和取值操作
Person p = new Person();
p.setAge(20);
System.out.println( p.getAge());
p.setName("李四");
System.out.println(p.getName());
}
構(gòu)造方法
構(gòu)造方法,稱為構(gòu)造器 (Constructor). 構(gòu)造方法也是方法,作用是創(chuàng)建對(duì)象的時(shí)候使用,可以為對(duì)象進(jìn)行初始化操作.
構(gòu)造方法定義和作用
- 權(quán)限修飾符
- 構(gòu)造方法,沒(méi)有返回值類型, void不能寫(xiě)
- 構(gòu)造方法的名字,有嚴(yán)格限制,必須和類名一致 (一模一樣)
- 構(gòu)造方法不需要return語(yǔ)句
- 作用 : 在創(chuàng)建對(duì)象的時(shí)候使用,其他的情況,和構(gòu)造方法無(wú)關(guān)
- 構(gòu)造方法的允許, new對(duì)象的時(shí)候才運(yùn)行,只運(yùn)行一次
/*
* 構(gòu)造方法的定義
*
* - 權(quán)限修飾符
- 構(gòu)造方法,沒(méi)有返回值類型, void不能寫(xiě)
- 構(gòu)造方法的名字,有嚴(yán)格限制,必須和類名一致 (一模一樣)
- 構(gòu)造方法不需要return語(yǔ)句
*/
public class Person {
//沒(méi)有參數(shù)構(gòu)造方法
public Person() {
System.out.println("無(wú)參數(shù)構(gòu)造方法");
}
public void eat() {
System.out.println("人在吃飯");
}
}
構(gòu)造方法實(shí)現(xiàn)對(duì)象的初始化
什么是對(duì)象的初始化操作 : 在對(duì)象的創(chuàng)建過(guò)程中,在new對(duì)象的時(shí)候,使用構(gòu)造方法,為成員變量賦值,這個(gè)動(dòng)作就稱為對(duì)象的初始化操作!
/*
* 使用構(gòu)造方法,對(duì)象初始化操作
* 為類中的成員變量賦值
*/
public class Person {
private String name;
private int age;
/*
* 為類中的成員變量賦值
* 成員變量的值,未知的,傳遞參數(shù)
* 參數(shù)接收姓名和年齡
*/
public Person(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 eat() {
System.out.println("人在吃飯");
}
}
public static void main(String[] args) {
//創(chuàng)建Person類對(duì)象
//建立對(duì)象,就是在調(diào)用構(gòu)造方法
//構(gòu)造方法需要傳遞參數(shù)
Person p = new Person("張三",20);
System.out.println(p);
p.eat();
//調(diào)用方法get獲取,成員變量的值
System.out.println(p.getName());
System.out.println(p.getAge());
}
思考問(wèn)題
構(gòu)造方法已經(jīng)完成了,對(duì)象初始化操作中,成員變量賦值了,我們是否還需要set方法賦值 ?
肯定需要,以后修改成員變量的數(shù)據(jù),使用set方法來(lái)實(shí)現(xiàn)
構(gòu)造方法的內(nèi)存
構(gòu)造方法也是方法,運(yùn)行必須進(jìn)入棧內(nèi)存
構(gòu)造方法的調(diào)用者是創(chuàng)建的對(duì)象 (創(chuàng)建對(duì)象,稱為實(shí)例化對(duì)象), 對(duì)象會(huì)將地址,傳遞到構(gòu)造方法的this關(guān)鍵字
對(duì)象的半初始化
對(duì)象進(jìn)入內(nèi)存,成員變量賦值,默認(rèn)值,到達(dá)這個(gè)步驟,稱為對(duì)象的半初始化狀態(tài)!
對(duì)象的創(chuàng)建順序 :
對(duì)象先在堆內(nèi)存中,劃分空間 (內(nèi)存地址有了)
初始化成員變量,賦值默認(rèn)值,賦值定義的值
對(duì)象調(diào)用構(gòu)造方法,為成員變量賦值
對(duì)象才會(huì)將地址,賦值到引用變量
p
默認(rèn)構(gòu)造方法
對(duì)于任何的一個(gè)類,都必須具有構(gòu)造方法.
- 默認(rèn)構(gòu)造方法
- 在一個(gè)類中,如果我們不去定義構(gòu)造方法,產(chǎn)生一個(gè)默認(rèn)的構(gòu)造方法,是有編譯器javac添加的
- 默認(rèn)構(gòu)造方法 : 無(wú)參數(shù)的構(gòu)造方法
public 構(gòu)造方法名(){}
- 如果我們自己手寫(xiě)了構(gòu)造方法,默認(rèn)的就沒(méi)有了
- 顯示定義構(gòu)造方法
- 我們自己的寫(xiě)的構(gòu)造方法,稱為顯示定義,無(wú)論構(gòu)造方法是怎么寫(xiě)的,默認(rèn)的就沒(méi)有了
構(gòu)造方法的重載
構(gòu)造方法也有重載特性 : 同一個(gè)類中,允許定義多個(gè)同名的方法,參數(shù)列表不同,就是重載.
構(gòu)造方法同樣可以定義多個(gè),只要他們之間重載即可
/*
* 構(gòu)造方法的重載特性
*/
public class Person {
private String name ;
private int age;
/*
* 帶有String和int類型的構(gòu)造方法
*/
public Person(String name , int age) {
this.name = name;
this.age = age;
System.out.println("有參數(shù)的構(gòu)造方法String和int");
}
//再次定義構(gòu)造方法,必須是重載形式的,無(wú)參數(shù)
public Person() {
System.out.println("無(wú)參數(shù)的構(gòu)造方法");
}
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 eat() {
System.out.println("人在吃飯");
}
}
public static void main(String[] args) {
//創(chuàng)建Person對(duì)象,使用無(wú)參數(shù)構(gòu)造方法
Person p = new Person();
p.setName("張三");
p.setAge(20);
System.out.println(p.getName());
System.out.println(p.getAge());
//創(chuàng)建Person對(duì)象,調(diào)用有參數(shù)的構(gòu)造方法
Person p2 = new Person("李四",22);
System.out.println(p2.getName());
System.out.println(p2.getAge());
}
this語(yǔ)句
this的另一種用法 :
- this.成員變量,區(qū)分成員變量和局部變量同名
- 語(yǔ)句用法
this()
- this語(yǔ)句的使用
-
this()
只能寫(xiě)在構(gòu)造方法的有效代碼第一行 -
this()
語(yǔ)句用來(lái)在構(gòu)造方法中,去調(diào)用另一個(gè)構(gòu)造方法 - this語(yǔ)句調(diào)用哪個(gè)構(gòu)造方法,看(傳遞的哪些參數(shù))
-
public Person(String name , int age) {
//調(diào)用無(wú)參數(shù)的構(gòu)造方法
this();
this.name = name;
this.age = age;
System.out.println("有參數(shù)的構(gòu)造方法String和int");
}
public Person() {
//調(diào)用有參數(shù)的構(gòu)造方法
//this();
System.out.println("無(wú)參數(shù)的構(gòu)造方法");
}
繼承
繼承,英語(yǔ)(extends) 擴(kuò)展; 延伸
通過(guò)一個(gè)例子,引出概念
學(xué)生和老師案例出現(xiàn)了重復(fù)的程序, 共性進(jìn)行了抽取,放在了另一個(gè)類中(Person類).只要學(xué)生類,老師類和Person類產(chǎn)生了某些關(guān)系,就直接可以使用Person類的內(nèi)容了
產(chǎn)生出了父子關(guān)系
, 在程序中稱為繼承關(guān)系
繼承 : 類和類之間產(chǎn)生的關(guān)系,繼承關(guān)系. 包含了父和子.
生活中的繼承和程序中繼承關(guān)系
實(shí)現(xiàn)繼承
繼承的關(guān)鍵字 extends
, 一個(gè)類繼承另一個(gè)類,使用該關(guān)鍵字
繼承的定義格式 :
public class A(子類) extends B(父類){
}
術(shù)語(yǔ) :
- A類,繼承B類, A稱為B的子類,又稱為派生類
- B類,稱為A的父類,又稱為超類,基類
繼承后 : 子類可以直接使用他父類的成員,不是全部
/*
* 父類 : 定義類,子類共有的內(nèi)容
* 成員變量,私有修飾
* 外面的類都不能使用了,包含子類
* 提供get / set
*/
public class Person {
private String name;
private int 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 class Student extends Person{
}
public class Teacher extends Person{
}
public static void main(String[] args) {
Student stu = new Student();
//stu對(duì)象,是Person的子類的對(duì)象
//子類的對(duì)象,調(diào)用父類的成員
stu.setName("張三"); //父類繼承的
stu.setAge(20);
System.out.println(stu.getName()); //父類繼承的
System.out.println(stu.getAge());
Teacher tea = new Teacher();
//tea對(duì)象,是Person的子類的對(duì)象
tea.setName("李四");
tea.setAge(50);
System.out.println(tea.getName());
System.out.println(tea.getAge());
}
繼承的好處
- 繼承是共性的抽取
- 繼承有效的減少代碼量
- 提高程序的復(fù)用性和擴(kuò)展性
- 面向?qū)ο蟮牡谌筇卣鞫鄳B(tài), 多態(tài)的實(shí)現(xiàn)前提就是繼承
繼承的弊端
- 繼承后,類和類之間的耦合性增強(qiáng) (緊密連接性)
- 一個(gè)類繼承另一個(gè)類后,不能再繼承其他類了 (單繼承弊端)
Java中的單繼承
- Java語(yǔ)言只支持單繼承,不支持多繼承
- 一個(gè)類只能同時(shí)繼承另一個(gè)類
- Java語(yǔ)言支持多層繼承,稱為多重繼承