Java面向對象(構造方法、this、super)


面向對象

今日內容介紹

u 構造方法

u this

u super

第1章 構造方法

我們對封裝已經有了基本的了解,接下來我們來看一個新的問題,依然以Person為例,由於Person中的屬性都被private了,外界無法直接訪問屬性,必須對外提供相應的setget方法。當創建人對象的時候,人對象一創建就要明確其姓名和年齡,那該怎么做呢?

1.1 構造方法介紹

在開發中經常需要在創建對象的同時明確對象的屬性值,比如員工入職公司就要明確他的姓名、年齡等屬性信息。

那么,創建對象就要明確屬性值,那怎么解決呢?也就是在創建對象的時候就要做的事情,當使用new關鍵字創建對象時,怎么給對象的屬性初始化值呢?這就要學習Java另外一門小技術,構造方法。

那什么是構造方法呢?從字面上理解即為構建創造時用的方法,即就是對象創建時要執行的方法。既然是對象創建時要執行的方法,那么只要在new對象時,知道其執行的構造方法是什么,就可以在執行這個方法的時候給對象進行屬性賦值。

l 構造方法的格式:

修飾符 構造方法名(參數列表)

{

}

l 構造方法的體現:

l 構造方法沒有返回值類型。也不需要寫返回值。因為它是為構建對象的,對象創建完,方法就執行結束。

l 構造方法名稱必須和類型保持一致。

l 構造方法沒有具體的返回值。

l 構造方法的代碼體現:

class Person {

// Person的成員屬性agename

private int age;

private String name;

 

// Person的構造方法,擁有參數列表

Person(int a, String nm) {

// 接受到創建對象時傳遞進來的值,將值賦給成員屬性

age = a;

name = nm;

}

}

1.2 構造方法調用和內存圖解

理解構造方法的格式和基本功能之后,現在就要研究構造方法是怎么執行的呢?在創建對象的時候是如何初始化的呢?

構造方法是專門用來創建對象的,也就是在new對象時要調用構造方法。現在來看看如何調用構造方法。

class Person {

// Person的成員屬性agename

private int age;

private String name;

 

// Person的構造方法,擁有參數列表

Person(int a, String nm) {

// 接受到創建對象時傳遞進來的值,將值賦給成員屬性

age = a;

name = nm;

}

 

public void speak() {

System.out.println("name=" + name + ",age=" + age);

}

}

 

class PersonDemo {

public static void main(String[] args) {

// 創建Person對象,並明確對象的年齡和姓名

Person p2 = new Person(23, "張三");

p2.speak();

}

}

上述代碼演示了創建對象時構造方法的調用。即在創建對象時,會調用與參數列表對應的構造方法。

上述代碼的圖解:

 

 

l 圖解說明:

1、首先會將main方法壓入棧中,執行main方法中的 new Person(23,"張三");

2、在堆內存中分配一片區域,用來存放創建的Person對象,這片內存區域會有屬於自己的內存地址(0x88)。然后給成員變量進行默認初始化(name=nullage=0)。

3、執行構造方法中的代碼(age = a ; name = nm;,將變量a對應的23賦值給age,將變量nm對應的張三賦值給name,這段代碼執行結束后,成員變量agename的值已經改變。執行結束之后構造方法彈棧,Person對象創建完成。將Person對象的內存地址0x88賦值給p2

1.3 默認構造方法和細節

在沒有學習構造方法之前,我們也可以通過new關鍵字創建對象,並調用相應的方法,同時在描述事物時也沒有寫構造方法。這是為什么呢?

在之前學習的過程中,描述事物時,並沒有顯示指定構造方法,當在編譯Java文件時,編譯器會自動給class文件中添加默認的構造方法。如果在描述類時,我們顯示指定了構造方法,那么,當在編譯Java源文件時,編譯器就不會再給class文件中添加默認構造方法。

class  Person {

//如果沒有顯示指定構造方法,編譯會在編譯時自動添加默認的構造方法

//Person(){}  //空參數的默認構造方法

}

 

當在描述事物時,要不要在類中寫構造方法呢?這時要根據描述事物的特點來確定,當描述的事物在創建其對象時就要明確屬性的值,這時就需要在定義類的時候書寫帶參數的構造方法。若創建對象時不需要明確具體的數據,這時可以不用書寫構造方法(不書寫也有默認的構造方法)。

l 構造方法的細節:

1、一個類中可以有多個構造方法,多個構造方法是以重載的形式存在的

2、構造方法是可以被private修飾的,作用:其他程序無法創建該類的對象。

class Person {

private int age;

private String name;

 

// 私有無參數的構造方法,即外界不能通過new Person();語句創建本類對象

private Person() {

}

 

// 多個構造方法是以重載的形式存在

Person(int a) {

age = a;

}

 

Person(String nm, int a) {

name = nm;

age = a;

}

}

1.4 構造方法和一般方法區別

到目前為止,學習兩種方法,分別為構造方法和一般方法,那么他們之間有什么異同呢?

構造方法在對象創建時就執行了,而且只執行一次。

一般方法是在對象創建后,需要使用時才被對象調用,並可以被多次調用。

l 問題:

有了構造方法之后可以對對象的屬性進行初始化,那么還需要對應的set和get方法嗎?

需要相應的setget方法,因為對象在創建之后需要修改和訪問相應的屬性值時,在這時只能通過set或者get方法來操作。

思考,如下代碼有問題嗎?

class Person {

void Person() {

}

}

 

class PersonDemo {

public static void main(String[] args) {

Person p = new Person();

}

}

 

第2章 this關鍵字

在之前學習方法時,我們知道方法之間是可以相互調用的,那么構造方法之間能不能相互調用呢?若可以,怎么調用呢?

2.1 this調用構造方法

在之前學習方法之間調用時,可以通過方法名進行調用。可是針對構造方法,無法通過構造方法名來相互調用。

構造方法之間的調用,可以通過this關鍵字來完成。

l 構造方法調用格式:

this(參數列表);

 

l 構造方法的調用

class Person {

// Person的成員屬性

private int age;

private String name;

 

// 無參數的構造方法

Person() {

}

 

// 給姓名初始化的構造方法

Person(String nm) {

name = nm;

}

 

// 給姓名和年齡初始化的構造方法

Person(String nm, int a) {

// 由於已經存在給姓名進行初始化的構造方法 name = nm;因此只需要調用即可

// 調用其他構造方法,需要通過this關鍵字來調用

this(nm);

// 給年齡初始化

age = a;

}

}

2.2 this的原理圖解

了解了構造方法之間是可以相互調用,那為什么他們之間通過this就可以調用呢?

通過上面的學習,簡單知道使用this可以實現構造方法之間的調用,但是為什么就會知道this調用哪一個構造方法呢?接下來需要圖解完成。

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);

}

}

 

 

l 圖列說明:

1、先執行main方法,main方法壓棧,執行其中的new Person(“張三”,23);

2、堆內存中開辟空間,並為其分配內存地址0x33,,緊接着成員變量默認初始化(name=null  age = 0);

3、擁有兩個參數的構造方法(PersonString nm , int a))壓棧,在這個構造方法中有一個隱式的this,因為構造方法是給對象初始化的,那個對象調用到這個構造方法,this就指向堆中的那個對象。

4、由於PersonString nm , int a)構造方法中使用了this(nm);構造方法Person(String nm)就會壓棧,並將“張三”傳遞給nm。在PersonString nm , int a)構造方法中同樣也有隱式的thisthis的值同樣也為0x33,這時會執行其中name = nm,即把“張三”賦值給成員的name。當賦值結束后PersonString nm , int a)構造方法彈棧。

5、程序繼續執行構造方法(PersonString nm , int a)中的age = a;這時會將23賦值給成員屬性age。賦值結束構造方法(PersonString nm , int a)彈棧。

6、當構造方法(PersonString nm , int a)彈棧結束后,Person對象在內存中創建完成,並將0x33賦值給main方法中的p引用變量。

l 注意:

this到底代表什么呢?this代表的是對象,具體代表哪個對象呢?哪個對象調用了this所在的方法,this就代表哪個對象。

調用其他構造方法的語句必須定義在構造方法的第一行,原因是初始化動作要最先執行。

2.3 成員變量和局部變量同名問題

通過上面學習,基本明確了對象初始化過程中的細節,也知道了構造方法之間的調用是通過this關鍵字完成的。但this也有另外一個用途,接下來我們就學習下。

當在方法中出現了局部變量和成員變量同名的時候,那么在方法中怎么區別局部變量成員變量呢?可以在成員變量名前面加上this.來區別成員變量和局部變量

class Person {

private int age;

private String name;

 

// 給姓名和年齡初始化的構造方法

Person(String name, int age) {

// 當需要訪問成員變量是,只需要在成員變量前面加上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();

}

}

2.4 this的應用

學習完了構造方法、this的用法之后,現在做個小小的練習。

需求:在Person類中定義功能,判斷兩個人是否是同齡人

class Person {

private int age;

private String name;

 

// 給姓名和年齡初始化的構造方法

Person(String name, int age) {

// 當需要訪問成員變量是,只需要在成員變量前面加上this.即可

this.name = name;

this.age = age;

}

 

public void speak() {

System.out.println("name=" + this.name + ",age=" + this.age);

}

 

// 判斷是否為同齡人

public boolean equalsAge(Person p) {

// 使用當前調用該equalsAge方法對象的age和傳遞進來page進行比較

// 由於無法確定具體是哪一個對象調用equalsAge方法,這里就可以使用this來代替

/*

 * if(this.age == p.age) { return true; } return false;

 */

return this.age = p.age;

}

}

 

第3章 super關鍵字

3.1 子父類中構造方法的調用

在創建子類對象時,父類的構造方法會先執行,因為子類中所有構造方法的第一行有默認的隱式super();語句。

格式:

調用本類中的構造方法

this(實參列表);

調用父類中的空參數構造方法

super();

調用父類中的有參數構造方法

super(實參列表);

 

為什么子類對象創建都要訪問父類中的構造方法?因為子類繼承了父類的內容,所以創建對象時,必須要先看父類是如何對其內容進行初始化的,看如下程序:

public class Test {

public static void main(String[] args) {

new Zi();

}

 

}

class Fu{

int num ;

Fu(){

System.out.println("Fu構造方法"+num);

num = 4;

}

}

class Zi extends Fu{

Zi(){

         //super(); 調用父類空參數構造方法

System.out.println("Zi構造方法"+num);

}

}

  執行結果:

       Fu構造方法0

       Zi構造方法4

 

通過結果發現,子類構造方法執行時中,調用了父類構造方法,這說明,子類構造方法中有一句super()

那么,子類中的構造方法為什么會有一句隱式的super()呢?

原因:子類會繼承父類中的內容,所以子類在初始化時,必須先到父類中去執行父類的初始化動作。這樣,才可以使用父類中的內容。

當父類中沒有空參數構造方法時,子類的構造方法必須有顯示的super語句,指定要訪問的父類有參數構造方法。

3.2 子類對象創建過程的細節

如果子類的構造方法第一行寫了this調用了本類其他構造方法,那么super調用父類的語句還有嗎?

這時是沒有的,因為this()或者super(),只能定義在構造方法的第一行,因為初始化動作要先執行。

父類構造方法中是否有隱式的super呢?

也是有的。記住:只要是構造方法默認第一行都是super();

父類的父類是誰呢?super調用的到底是誰的構造方法呢?

Java體系在設計,定義了一個所有對象的父類Object

 

l 注意:

類中的構造方法默認第一行都有隱式的super()語句,在訪問父類中的空參數構造方法。所以父類的構造方法既可以給自己的對象初始化,也可以給自己的子類對象初始化。

如果默認的隱式super()語句在父類中沒有對應的構造方法,那么必須在構造方法中通過this或者super的形式明確要調用的構造方法。

3.3 super應用

練習:描述學生和工人這兩個類,將他們的共性nameage抽取出來存放在父類中,並提供相應的getset方法,同時需要在創建學生和工人對象就必須明確姓名和年齡

//定義Person類,將StudentWorker共性抽取出來

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類的構造方法

Student(String name, int age) {

// 使用super關鍵字調用父類構造方法,進行相應的初始化動作

super(name, age);

}

public void study() {// Studnet中特有的方法

System.out.println(this.getName() + "同學在學習");

}

}

class Worker extends Person {

Worker(String name, int age) {

// 使用super關鍵字調用父類構造方法,進行相應的初始化動作

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();

}

}

 

第4章 綜合案例---完整的員工類

4.1 案例介紹

IT公司有多名員工,按照員工負責的工作不同,進行了部門的划分(研發部員工、維護部員工)。研發部根據所需研發的內容不同,又分為JavaEE工程師、Android工程師;維護部根據所需維護的內容不同,又分為網絡維護工程師、硬件維護工程師。

公司的每名員工都有他們自己的員工編號、姓名,並要做它們所負責的工作。

l 工作內容

l JavaEE工程師:員工號為xxx的 xxx員工,正在研發淘寶網站

l Android工程師:員工號為xxx的 xxx員工,正在研發淘寶手機客戶端軟件

網絡維護工程師:員工號為xxx的 xxx員工,正在檢查網絡是否暢通

硬件維護工程師:員工號為xxx的 xxx員工,正在修復打印機

請根據描述,完成員工體系中所有類的定義,並指定類之間的繼承關系。進行XX工程師類的對象創建,完成工作方法的調用。

4.2 案例分析

l 根據上述部門的描述,得出如下的員工體系圖

 

 

l 根據員工信息的描述,確定每個員工都有員工編號、姓名、要進行工作。則,把這些共同的屬性與功能抽取到父類中(員工類),關於工作的內容由具體的工程師來進行指定。

l 工作內容

l JavaEE工程師:員工號為xxx的 xxx員工,正在研發淘寶網站

l Android工程師:員工號為xxx的 xxx員工,正在研發淘寶手機客戶端軟件

網絡維護工程師:員工號為xxx的 xxx員工,正在檢查網絡是否暢通

硬件維護工程師:員工號為xxx的 xxx員工,正在修復打印機

創建JavaEE工程師對象,完成工作方法的調用

4.3 案例代碼實現

l 根據員工體系圖,完成類的定義

定義員工類(抽象類)

public abstract class Employee {

private String id;// 員工編號

private String name; // 員工姓名

 

//空參數構造方法

public Employee() {

super();

}

//有參數構造方法

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();

}

 

定義研發部員工類Developer 繼承 員工類Employee

public abstract class Developer extends Employee {

//空參數構造方法

public Developer() {

super();

}

//有參數構造方法

public Developer(String id, String name) {

super(id, name);

}

}

 

定義維護部員工類Maintainer 繼承 員工類Employee

public abstract class Maintainer extends Employee {

//空參數構造方法

public Maintainer() {

super();

}

//有參數構造方法

public Maintainer(String id, String name) {

super(id, name);

}

}

 

定義JavaEE工程師 繼承 研發部員工類,重寫工作方法

public class JavaEE extends Developer {

//空參數構造方法

public JavaEE() {

super();

}

//有參數構造方法

public JavaEE(String id, String name) {

super(id, name);

}

 

@Override

public void work() {

System.out.println("員工號為 " + getId() + " " + getName() + " 員工,正在研發淘寶網站");

}

}

 

定義Android工程師 繼承 研發部員工類,重寫工作方法

public class Android extends Developer {

//空參數構造方法

public Android() {

super();

}

//有參數構造方法

public Android(String id, String name) {

super(id, name);

}

 

@Override

public void work() {

System.out.println("員工號為 " + getId() + " " + getName() + " 員工,正在研發淘寶手機客戶端軟件");

}

}

 

定義Network網絡維護工程師 繼承 維護部員工類,重寫工作方法

public class Network extends Maintainer {

//空參數構造方法

public Network() {

super();

}

//有參數構造方法

public Network(String id, String name) {

super(id, name);

}

 

@Override

public void work() {

System.out.println("員工號為 " + getId() + " " + getName() + " 員工,正在檢查網絡是否暢通");

}

}

 

定義Hardware硬件維護工程師 繼承 維護部員工類,重寫工作方法

public class Hardware extends Maintainer {

//空參數構造方法

public Hardware() {

super();

}

//有參數構造方法

public Hardware(String id, String name) {

super(id, name);

}

 

@Override

public void work() {

System.out.println("員工號為 " + getId() + " " + getName() + " 員工,正在修復打印機");

}

}

 

在測試類中,創建JavaEE工程師對象,完成工作方法的調用

public class Test {

public static void main(String[] args) {

//創建JavaEE工程師員工對象該員工的編號000015員工的姓名 小明

JavaEE ee = new JavaEE("000015", "小明");

//調用該員工的工作方法

ee.work();

}

}

第5章 總結

5.1 知識點總結

l this關鍵字

l this關鍵字,本類對象的引用

l this是在方法中使用的,哪個對象調用了該方法,那么,this就代表調用該方法的對象引用

l this什么時候存在的?當創建對象的時候,this存在的

l this的作用:用來區別同名的成員變量與局部變量(this.成員變量)

public void setName(String name) {

this.name = name;

}

構造方法: 用來給類的成員進行初始化操作

格式:

修飾符 類名 (參數列表) {

...

}

l 構造方法的特點:

l 1, 方法名與類名相同

l 2,沒有返回值,也沒有返回值類型,連void也沒有

l 構造方法什么時候會被調用執行?

只有在創建對象的時候才可以被調用

 

l super: 指的是父類的存儲空間(理解為父類的引用)

調用父類的成員變量:

super.成員變量;

調用父類的構造方法:

super(參數);

調用方法的成員方法:

super.成員方法();

l 繼承中的構造方法注意事項:

1,如果我們手動給出了構造方法,編譯器不會在給我們提供默認的空參數構造方法

   如果我們沒寫任何的構造方法,編譯器提供給我們一個空參數構造方法

2, 在構造方法中,默認的第一條語句為 super();

   它是用來訪問父類中的空參數構造方法,進行父類成員的初始化操作

3, 當父類中沒有空參數構造方法的時候,怎么辦?

a: 通過 super(參數) 訪問父類有參數的構造方法

b: 通過 this(參數) 訪問本類中其他構造方法

   注意:[本類中的其他構造方法已經能夠正常訪問父類構造方法]

4, super(參數) 與 this(參數) 不能同時在構造方法中存在

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM