01構(gòu)造方法引入
* A:構(gòu)造方法的引入
在開發(fā)中經(jīng)常需要在創(chuàng)建對象的同時明確對象的屬性值,比如員工入職公司就要明確他的姓名、年齡等屬性信息。
那么,創(chuàng)建對象就要明確屬性值,那怎么解決呢?也就是在創(chuàng)建對象的時候就要做的事情,當(dāng)使用new關(guān)鍵字創(chuàng)建對象時,怎么給對象的屬性初始化值呢?
這就要學(xué)習(xí)Java另外一門小技術(shù),構(gòu)造方法。
* B: 那什么是構(gòu)造方法呢?
從字面上理解即為構(gòu)建創(chuàng)造時用的方法,即就是對象創(chuàng)建時要執(zhí)行的方法。既然是對象創(chuàng)建時要執(zhí)行的方法,那么只要在new對象時,
知道其執(zhí)行的構(gòu)造方法是什么,就可以在執(zhí)行這個方法的時候給對象進行屬性賦值。
02構(gòu)造方法作用
* A: 構(gòu)造方法的作用:
在new的同時給成員變量賦值,給對象屬性進行初始化。
* B: 舉例:
Perons p = new Person("張三",23); 在new 的時候給p對象的name屬性和age屬性進行賦值,使這個對象的屬性有值。
03構(gòu)造方法的定義和運行特點
* A: 構(gòu)造方法定義
構(gòu)造方法的格式:
修飾符 構(gòu)造方法名(參數(shù)列表)
{
}
* B: 構(gòu)造方法的體現(xiàn):
構(gòu)造方法沒有返回值類型。也不需要寫返回值。因為它是為構(gòu)建對象的,對象創(chuàng)建完,方法就執(zhí)行結(jié)束。
構(gòu)造方法名稱必須和類型保持一致。
構(gòu)造方法沒有具體的返回值。
構(gòu)造方法的代碼體現(xiàn):
* C: 構(gòu)造方法舉例
class Person {
// Person的成員屬性age和name
private int age;
private String name;
// Person的構(gòu)造方法,擁有參數(shù)列表
Person(int a, String nm) {
// 接受到創(chuàng)建對象時傳遞進來的值,將值賦給成員屬性
age = a;
name = nm;
}
}
* D: 構(gòu)造方法運行特點:
在new 對象的時候自動調(diào)用執(zhí)行。
04默認添加的構(gòu)造方法
* A: 每一class類都必須有一個構(gòu)造方法,構(gòu)造方法不寫也有。
編譯的時候,javac,系統(tǒng)會自動檢查類中是否有構(gòu)造方法,如果沒有編譯器就會自動添加一個構(gòu)造方法
比如Person類, 編譯器添加一個無參構(gòu)造 public Person(){}
05構(gòu)造方法的調(diào)用賦值
* A: 理解構(gòu)造方法的格式和基本功能之后,現(xiàn)在就要研究構(gòu)造方法是怎么執(zhí)行的呢?在創(chuàng)建對象的時候是如何初始化的呢?
構(gòu)造方法是專門用來創(chuàng)建對象的,也就是在new對象時要調(diào)用構(gòu)造方法?,F(xiàn)在來看看如何調(diào)用構(gòu)造方法。
* B: 案例
class Person {
// Person的成員屬性age和name
private int age;
private String name;
// Person的構(gòu)造方法,擁有參數(shù)列表
Person(int a, String nm) {
// 接受到創(chuàng)建對象時傳遞進來的值,將值賦給成員屬性
age = a;
name = nm;
}
public void speak() {
System.out.println("name=" + name + ",age=" + age);
}
}
class PersonDemo {
public static void main(String[] args) {
// 創(chuàng)建Person對象,并明確對象的年齡和姓名
Person p2 = new Person(23, "張三");
p2.speak();
}
}
上述代碼演示了創(chuàng)建對象時構(gòu)造方法的調(diào)用。即在創(chuàng)建對象時,會調(diào)用與參數(shù)列表對應(yīng)的構(gòu)造方法
06構(gòu)造方法的內(nèi)存
A:內(nèi)存加載的過程
有一個Person類, 創(chuàng)建Person 對象new Person()
1、首先會將main方法壓入棧中,執(zhí)行main方法中的 new Person(23,"張三");
2、在堆內(nèi)存中分配一片區(qū)域,用來存放創(chuàng)建的Person對象,這片內(nèi)存區(qū)域會有屬于自己的內(nèi)存地址(0x88)。然后給成員變量進行默認初始化(name=null,age=0)。
3、執(zhí)行構(gòu)造方法中的代碼(age = a ; name = nm;),將變量a對應(yīng)的23賦值給age,將變量nm對應(yīng)的”張三賦值給name,這段代碼執(zhí)行結(jié)束后,成員變量age和name的值已經(jīng)改變。執(zhí)行結(jié)束之后構(gòu)造方法彈棧,Person對象創(chuàng)建完成。將Person對象的內(nèi)存地址0x88賦值給p2。
==============================第二節(jié)課開始====================================
07構(gòu)造方法的重載
* A:當(dāng)在描述事物時,要不要在類中寫構(gòu)造方法呢?這時要根據(jù)描述事物的特點來確定,當(dāng)描述的事物在創(chuàng)建其對象時就要明確屬性的值,這時就需要在定義類的時候書寫帶參數(shù)的構(gòu)造方法。
* 若創(chuàng)建對象時不需要明確具體的數(shù)據(jù),這時可以不用書寫構(gòu)造方法(不書寫也有默認的構(gòu)造方法)。
構(gòu)造方法的細節(jié):
1、一個類中可以有多個構(gòu)造方法,多個構(gòu)造方法是以重載的形式存在的
2、構(gòu)造方法是可以被private修飾的,作用:其他程序無法創(chuàng)建該類的對象。
* B: 舉例
class Person {
private int age;
private String name;
// 私有無參數(shù)的構(gòu)造方法,即外界不能通過new Person();語句創(chuàng)建本類對象
private Person() {
}
// 多個構(gòu)造方法是以重載的形式存在
Person(int a) {
age = a;
}
Person(String nm, int a) {
name = nm;
age = a;
}
}
08構(gòu)造方法和一般方法區(qū)別
* A: 目前為止,學(xué)習(xí)兩種方法,分別為構(gòu)造方法和一般方法,那么他們之間有什么異同呢?
1.格式不同
構(gòu)造方法 : 修飾符 類名(參數(shù)類型 參數(shù) ...){
初始化成員變量
}
一般方法: 需要有返回值類型
2.作用不同
構(gòu)造方法一般用來給成員變量初始化;
一般方法根據(jù)需求而定;
3.調(diào)用方式不同
構(gòu)造方法創(chuàng)建對象時調(diào)用, 或者this() super() 語句調(diào)用
普通方法需要對象調(diào)用或者靜態(tài)方法直接調(diào)用靜態(tài)方法.
4.執(zhí)行不同
構(gòu)造方法在對象創(chuàng)建時就執(zhí)行了,而且只執(zhí)行一次。
一般方法是在對象創(chuàng)建后,需要使用時才被對象調(diào)用,并可以被多次調(diào)用。
09this在構(gòu)造方法之間的調(diào)用
* A: 在之前學(xué)習(xí)方法之間調(diào)用時,可以通過方法名進行調(diào)用。可是針對構(gòu)造方法,無法通過構(gòu)造方法名來相互調(diào)用。
構(gòu)造方法之間的調(diào)用,可以通過this關(guān)鍵字來完成。
構(gòu)造方法調(diào)用格式:
this(參數(shù)列表);
* B:調(diào)用構(gòu)造方法的案例
class Person {
// Person的成員屬性
private int age;
private String name;
// 無參數(shù)的構(gòu)造方法
Person() {
}
// 給姓名初始化的構(gòu)造方法
Person(String nm) {
name = nm;
}
// 給姓名和年齡初始化的構(gòu)造方法
Person(String nm, int a) {
// 由于已經(jīng)存在給姓名進行初始化的構(gòu)造方法 name = nm;因此只需要調(diào)用即可
// 調(diào)用其他構(gòu)造方法,需要通過this關(guān)鍵字來調(diào)用
this(nm);
// 給年齡初始化
age = a;
}
}
10this在構(gòu)造方法調(diào)用的內(nèi)存圖
* A: 被加載的代碼
class Person {
private int age;
private String name;
Person() {
}
Person(String nm) {
name = nm;
}
Person(String nm, int a) {
this(nm);
age = a;
}
}
class PersonDemo {
public static void main(String[] args) {
Person p = new Person("張三", 23);
}
}
* B: 構(gòu)造方法調(diào)用的原理圖
* 圖略
1、先執(zhí)行main方法,main方法壓棧,執(zhí)行其中的new Person(“張三”,23);
2、堆內(nèi)存中開辟空間,并為其分配內(nèi)存地址0x33,,緊接著成員變量默認初始化(name=null age = 0);
3、擁有兩個參數(shù)的構(gòu)造方法(Person(String nm , int a))壓棧,在這個構(gòu)造方法中有一個隱式的this,因為構(gòu)造方法是給對象初始化的,那個對象調(diào)用到這個構(gòu)造方法,this就指向堆中的那個對象。
4、由于Person(String nm , int a)構(gòu)造方法中使用了this(nm);構(gòu)造方法Person(String nm)就會壓棧,并將“張三”傳遞給nm。在Person(String nm , int a)構(gòu)造方法中同樣也有隱式的this,this的值同樣也為0x33,這時會執(zhí)行其中name = nm,即把“張三”賦值給成員的name。當(dāng)賦值結(jié)束后Person(String nm , int a)構(gòu)造方法彈棧。
5、程序繼續(xù)執(zhí)行構(gòu)造方法(Person(String nm , int a)中的age = a;這時會將23賦值給成員屬性age。賦值結(jié)束構(gòu)造方法(Person(String nm , int a)彈棧。
6、當(dāng)構(gòu)造方法(Person(String nm , int a)彈棧結(jié)束后,Person對象在內(nèi)存中創(chuàng)建完成,并將0x33賦值給main方法中的p引用變量。
注意:
this到底代表什么呢?this代表的是對象,具體代表哪個對象呢?哪個對象調(diào)用了this所在的方法,this就代表哪個對象。
調(diào)用其他構(gòu)造方法的語句必須定義在構(gòu)造方法的第一行,原因是初始化動作要最先執(zhí)行。
11this簡易應(yīng)用
* A: 當(dāng)在方法中出現(xiàn)了局部變量和成員變量同名的時候,那么在方法中怎么區(qū)別局部變量成員變量呢?可以在成員變量名前面加上this.來區(qū)別成員變量和局部變量
* B: 舉例1
class Person {
private int age;
private String name;
// 給姓名和年齡初始化的構(gòu)造方法
Person(String name, int age) {
// 當(dāng)需要訪問成員變量是,只需要在成員變量前面加上this.即可
this.name = name;
this.age = age;
}
public void speak() {
System.out.println("name=" + this.name + ",age=" + this.age);
}
}
class PersonDemo {
public static void main(String[] args) {
Person p = new Person("張三", 23);
p.speak();
}
}
* C: 舉例2
學(xué)習(xí)完了構(gòu)造方法、this的用法之后,現(xiàn)在做個小小的練習(xí)。
需求:在Person類中定義功能,判斷兩個人是否是同齡人
class Person {
private int age;
private String name;
// 給姓名和年齡初始化的構(gòu)造方法
Person(String name, int age) {
// 當(dāng)需要訪問成員變量是,只需要在成員變量前面加上this.即可
this.name = name;
this.age = age;
}
public void speak() {
System.out.println("name=" + this.name + ",age=" + this.age);
}
// 判斷是否為同齡人
public boolean equalsAge(Person p) {
// 使用當(dāng)前調(diào)用該equalsAge方法對象的age和傳遞進來p的age進行比較
// 由于無法確定具體是哪一個對象調(diào)用equalsAge方法,這里就可以使用this來代替
/*
* if(this.age == p.age) { return true; } return false;
*/
return this.age = p.age;
}
}
==============================第三節(jié)課開始====================================
12super關(guān)鍵字_1
* A: 子父類中構(gòu)造方法的調(diào)用
在創(chuàng)建子類對象時,父類的構(gòu)造方法會先執(zhí)行,因為子類中所有構(gòu)造方法的第一行有默認的隱式super();語句。
* B: 格式:
調(diào)用本類中的構(gòu)造方法
this(實參列表);
調(diào)用父類中的空參數(shù)構(gòu)造方法
super();
調(diào)用父類中的有參數(shù)構(gòu)造方法
super(實參列表);
13super關(guān)鍵字_2
* A:子類構(gòu)造方法,有一個默認添加的構(gòu)造方法
public class Student extends Person {
public Student(){
super();
}
}
* B :為什么子類對象創(chuàng)建都要訪問父類中的構(gòu)造方法?因為子類繼承了父類的內(nèi)容,所以創(chuàng)建對象時,必須要先看父類是如何對其內(nèi)容進行初始化的,看如下程序
public class Test {
public static void main(String[] args) {
new Zi();
}
}
class Fu{
int num ;
Fu(){
System.out.println("Fu構(gòu)造方法"+num);
num = 4;
}
}
class Zi extends Fu{
Zi(){
//super(); 調(diào)用父類空參數(shù)構(gòu)造方法
System.out.println("Zi構(gòu)造方法"+num);
}
}
執(zhí)行結(jié)果:
Fu構(gòu)造方法0
Zi構(gòu)造方法4
通過結(jié)果發(fā)現(xiàn),子類構(gòu)造方法執(zhí)行時中,調(diào)用了父類構(gòu)造方法,這說明,子類構(gòu)造方法中有一句super()。
那么,子類中的構(gòu)造方法為什么會有一句隱式的super()呢?
原因:子類會繼承父類中的內(nèi)容,所以子類在初始化時,必須先到父類中去執(zhí)行父類的初始化動作。這樣,才可以使用父類中的內(nèi)容。
當(dāng)父類中沒有空參數(shù)構(gòu)造方法時,子類的構(gòu)造方法必須有顯示的super語句,指定要訪問的父類有參數(shù)構(gòu)造方法。
14子類父類的內(nèi)存圖
略:
具體見 day12_source/子類父類的內(nèi)存圖.JPG
15super關(guān)鍵字_3
* A: 創(chuàng)建子類對象的時候會必須調(diào)用父類的構(gòu)造方法。
子類默認會調(diào)用父類的無參構(gòu)造, 但如果父類沒有無參構(gòu)造,子類的構(gòu)造方法繼續(xù)調(diào)用父類的無參構(gòu)造就會報錯。
因此子類構(gòu)造方法的第一行需要調(diào)用父類的構(gòu)造方法,既可以調(diào)用父類的無參構(gòu)造,也可以調(diào)用父類的有參構(gòu)造,這樣語法上就不會報錯。
16super關(guān)鍵字_4
* A: 構(gòu)造方法第一行,寫this()還是super()
* this() 是調(diào)用本類的構(gòu)造方法,super()是調(diào)用父類的構(gòu)造方法, 且兩條語句不能同時存在
* 保證子類的所有構(gòu)造方法調(diào)用到父類的構(gòu)造方法即可
* B: 小結(jié):
* 無論如何,子類的所有構(gòu)造方法,直接或間接必須調(diào)用到父類構(gòu)造方法;
* 子類的構(gòu)造方法什么都不寫,默認的構(gòu)造方法第一行super()
17創(chuàng)建子類對象過程的細節(jié)
* A 創(chuàng)建子類對象過程的細節(jié)
* 如果子類的構(gòu)造方法第一行寫了this調(diào)用了本類其他構(gòu)造方法,那么super調(diào)用父類的語句還有嗎?
* 這時是沒有的,因為this()或者super(),只能定義在構(gòu)造方法的第一行,因為初始化動作要先執(zhí)行。
* 父類構(gòu)造方法中是否有隱式的super呢?
* 也是有的。記?。褐灰菢?gòu)造方法默認第一行都是super();
* 父類的父類是誰呢?super調(diào)用的到底是誰的構(gòu)造方法呢?
* Java體系在設(shè)計,定義了一個所有對象的父類Object
* 注意:
類中的構(gòu)造方法默認第一行都有隱式的super()語句,在訪問父類中的空參數(shù)構(gòu)造方法。所以父類的構(gòu)造方法既可以給自己的對象初始化,也可以給自己的子類對象初始化。
如果默認的隱式super()語句在父類中沒有對應(yīng)的構(gòu)造方法,那么必須在構(gòu)造方法中通過this或者super的形式明確要調(diào)用的構(gòu)造方法。
==============================第四節(jié)課開始====================================
18super的應(yīng)用
* A: 練習(xí):描述學(xué)生和工人這兩個類,將他們的共性name和age抽取出來存放在父類中,并提供相應(yīng)的get和set方法,同時需要在創(chuàng)建學(xué)生和工人對象就必須明確姓名和年齡
* 案例:
//定義Person類,將Student和Worker共性抽取出來
class Person {
private String name;
private int age;
public Person(String name, int age) {
// super();
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;
}
}
class Student extends Person {
// Student類的構(gòu)造方法
Student(String name, int age) {
// 使用super關(guān)鍵字調(diào)用父類構(gòu)造方法,進行相應(yīng)的初始化動作
super(name, age);
}
public void study() {// Studnet中特有的方法
System.out.println(this.getName() + "同學(xué)在學(xué)習(xí)");
}
}
class Worker extends Person {
Worker(String name, int age) {
// 使用super關(guān)鍵字調(diào)用父類構(gòu)造方法,進行相應(yīng)的初始化動作
super(name, age);
}
public void work() {// Worker 中特有的方法
System.out.println(this.getName() + "工人在工作");
}
}
public class Test {
public static void main(String[] args) {
Student stu = new Student("小明",23);
stu.study();
Worker w = new Worker("小李",45);
w.work();
}
}
19完整員工案例分析
* A: 項目介紹
某IT公司有多名員工,按照員工負責(zé)的工作不同,進行了部門的劃分(研發(fā)部員工、維護部員工)。研發(fā)部根據(jù)所需研發(fā)的內(nèi)容不同,又分為JavaEE工程師、Android工程師;維護部根據(jù)所需維護的內(nèi)容不同,又分為網(wǎng)絡(luò)維護工程師、硬件維護工程師。
公司的每名員工都有他們自己的員工編號、姓名,并要做它們所負責(zé)的工作。
工作內(nèi)容
JavaEE工程師:員工號為xxx的 xxx員工,正在研發(fā)淘寶網(wǎng)站
Android工程師:員工號為xxx的 xxx員工,正在研發(fā)淘寶手機客戶端軟件
網(wǎng)絡(luò)維護工程師:員工號為xxx的 xxx員工,正在檢查網(wǎng)絡(luò)是否暢通
硬件維護工程師:員工號為xxx的 xxx員工,正在修復(fù)打印機
請根據(jù)描述,完成員工體系中所有類的定義,并指定類之間的繼承關(guān)系。進行XX工程師類的對象創(chuàng)建,完成工作方法的調(diào)用。
* B: 案例分析
根據(jù)上述部門的描述,得出如下的員工體系圖
根據(jù)員工信息的描述,確定每個員工都有員工編號、姓名、要進行工作。則,把這些共同的屬性與功能抽取到父類中(員工類),關(guān)于工作的內(nèi)容由具體的工程師來進行指定。
工作內(nèi)容
JavaEE工程師:員工號為xxx的 xxx員工,正在研發(fā)淘寶網(wǎng)站
Android工程師:員工號為xxx的 xxx員工,正在研發(fā)淘寶手機客戶端軟件
網(wǎng)絡(luò)維護工程師:員工號為xxx的 xxx員工,正在檢查網(wǎng)絡(luò)是否暢通
硬件維護工程師:員工號為xxx的 xxx員工,正在修復(fù)打印機
創(chuàng)建JavaEE工程師對象,完成工作方法的調(diào)用
20案例代碼實現(xiàn)
* A:定義員工類(抽象類)
public abstract class Employee {
private String id;// 員工編號
private String name; // 員工姓名
//空參數(shù)構(gòu)造方法
public Employee() {
super();
}
//有參數(shù)構(gòu)造方法
public Employee(String id, String name) {
super();
this.id = id;
this.name = name;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
//工作方法(抽象方法)
public abstract void work();
}
* B : 定義研發(fā)部員工類Developer 繼承 員工類Employee
public abstract class Developer extends Employee {
//空參數(shù)構(gòu)造方法
public Developer() {
super();
}
//有參數(shù)構(gòu)造方法
public Developer(String id, String name) {
super(id, name);
}
}
* C: 定義維護部員工類Maintainer 繼承 員工類Employee
public abstract class Maintainer extends Employee {
//空參數(shù)構(gòu)造方法
public Maintainer() {
super();
}
//有參數(shù)構(gòu)造方法
public Maintainer(String id, String name) {
super(id, name);
}
}
* D: 定義JavaEE工程師 繼承 研發(fā)部員工類,重寫工作方法
public class JavaEE extends Developer {
//空參數(shù)構(gòu)造方法
public JavaEE() {
super();
}
//有參數(shù)構(gòu)造方法
public JavaEE(String id, String name) {
super(id, name);
}
@Override
public void work() {
System.out.println("員工號為 " + getId() + " 的 " + getName() + " 員工,正在研發(fā)淘寶網(wǎng)站");
}
}
* E: 定義Android工程師 繼承 研發(fā)部員工類,重寫工作方法
public class Android extends Developer {
//空參數(shù)構(gòu)造方法
public Android() {
super();
}
//有參數(shù)構(gòu)造方法
public Android(String id, String name) {
super(id, name);
}
@Override
public void work() {
System.out.println("員工號為 " + getId() + " 的 " + getName() + " 員工,正在研發(fā)淘寶手機客戶端軟件");
}
}
* F: 定義Network網(wǎng)絡(luò)維護工程師 繼承 維護部員工類,重寫工作方法
public class Network extends Maintainer {
//空參數(shù)構(gòu)造方法
public Network() {
super();
}
//有參數(shù)構(gòu)造方法
public Network(String id, String name) {
super(id, name);
}
@Override
public void work() {
System.out.println("員工號為 " + getId() + " 的 " + getName() + " 員工,正在檢查網(wǎng)絡(luò)是否暢通");
}
}
* G: 定義Hardware硬件維護工程師 繼承 維護部員工類,重寫工作方法
public class Hardware extends Maintainer {
//空參數(shù)構(gòu)造方法
public Hardware() {
super();
}
//有參數(shù)構(gòu)造方法
public Hardware(String id, String name) {
super(id, name);
}
@Override
public void work() {
System.out.println("員工號為 " + getId() + " 的 " + getName() + " 員工,正在修復(fù)打印機");
}
}
* H: 在測試類中,創(chuàng)建JavaEE工程師對象,完成工作方法的調(diào)用
public class Test {
public static void main(String[] args) {
//創(chuàng)建JavaEE工程師員工對象,該員工的編號000015,員工的姓名 小明
JavaEE ee = new JavaEE("000015", "小明");
//調(diào)用該員工的工作方法
ee.work();
}
}
21總結(jié)
* 把今天的知識點總結(jié)一遍。