一偿短、介紹
在繼承中欣孤,我們子類繼承了父類,并沒(méi)有繼承他的構(gòu)造方法昔逗,所以我們要了解的是子類與父類的構(gòu)造方法的處理降传。
二、知識(shí)點(diǎn)介紹
1纤子、繼承關(guān)系內(nèi)存解釋
2搬瑰、父類對(duì)象優(yōu)于子類對(duì)象產(chǎn)生
3、super關(guān)鍵字
4控硼、this關(guān)鍵字
5泽论、super與this比較
6、對(duì)多態(tài)向上向下轉(zhuǎn)型的內(nèi)存解釋
三卡乾、上課視頻對(duì)應(yīng)說(shuō)明文檔
1翼悴、繼承關(guān)系內(nèi)存解釋
實(shí)際上在面向?qū)ο蟮谝惶斓闹v解當(dāng)中,我們對(duì)內(nèi)存方面做了一些隱瞞幔妨。因?yàn)槌薕bject類鹦赎,所有的類都是有父類的。但是我們?cè)诳紤]內(nèi)存圖時(shí)忽略了這點(diǎn)误堡,現(xiàn)在古话,我們來(lái)簡(jiǎn)單描述加入了子父類關(guān)系后的對(duì)象內(nèi)存圖。
以Person類為例:
//定義父類
public class Person {
private String name;
private int age;
public Person(){}
public Person(String name,int age) {
this.name = name;
this.age = age;
}
//get/set方法
}
//定義子類
public class Chinese extends Person{
private Stirng address;
public Chinese(){}
public Chinese(String name,int age,String address) {
super(name,age);
this.address = address;
}
//對(duì)address的get/set
}
//定義測(cè)試類,使用子類創(chuàng)建對(duì)象
public class Test{
Chinese c = new Chinese(“AngelaBaby”,18,”北京海淀區(qū)上地7街晉福公寓”);
}
對(duì)象內(nèi)存圖
代碼示例:
/*
* 自定義類型Person 類
*
* name? age
*
* 吃? 睡
*/
public abstract class Person {
private String name;
int age;
//定義無(wú)參構(gòu)造方法
public Person(){
//方法邏輯
System.out.println("我是Person的無(wú)參構(gòu)造");
}
//定義帶參構(gòu)造一般都是為了給成員變量賦值
public Person(String name ,int age){
System.out.println("我是Person帶參構(gòu)造給成員變量賦值");
this.name = name;
this.age = age;
}
private void eat(){
System.out.println("吃");
}
public void sleep(){
System.out.println("睡");
}
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;
}
}
/*
* 自定義Studnet繼承Person類
*/
public class Student extends Person{
private String number;
/*
* 無(wú)參構(gòu)造
*/
public Student() {
System.out.println("Studnet的無(wú)參構(gòu)造");
}
//帶參構(gòu)造
public Student(String number,String name,int age) {
System.out.println("Studnet的帶參構(gòu)造");
this.number = number;
}
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
}
/*
* 測(cè)試有繼承關(guān)系的構(gòu)造方法
*/
public class Test {
public static void main(String[] args) {
//Student s = new Student();
Student s2 = new Student("2016");
}
}?
2锁施、父類對(duì)象優(yōu)于子類對(duì)象產(chǎn)生
在每次創(chuàng)建子類對(duì)象時(shí)陪踩,我們均會(huì)先創(chuàng)建父類對(duì)象杖们,再創(chuàng)建其子類對(duì)象本身。目的在于子類對(duì)象中包含了其對(duì)應(yīng)的父類對(duì)象肩狂,便可以包含其父類對(duì)象的成員摘完,如果父類成員非private修飾,則子類可以隨意使用父類成員傻谁。
反之孝治,如果沒(méi)有先創(chuàng)建父類對(duì)象就使用了子類對(duì)象,則子類無(wú)法使用父類的成員审磁。抽象類包含構(gòu)造方法的原因就在于其僅僅是為了給成員變量賦值谈飒,供子類使用。
這里我們需要注意的是力图,內(nèi)存當(dāng)中實(shí)際是存在抽象類的對(duì)象空間的步绸,我們無(wú)法直接創(chuàng)建抽象類對(duì)象,但是子類可以吃媒,在子類的內(nèi)存空間中包括了這個(gè)抽象父類對(duì)象瓤介。
3、super關(guān)鍵字
3.1赘那、super關(guān)鍵字概念
super代表本類對(duì)象中包含的父類對(duì)象空間的引用刑桑。
當(dāng)有了繼承關(guān)系后,創(chuàng)建一個(gè)子類對(duì)象時(shí)募舟,會(huì)先在子類中創(chuàng)建其父類對(duì)象祠斧,則子類對(duì)象包含了父類的所有方法與屬性,而其非私有的方法一般都可以訪問(wèn) (在完成訪問(wèn)權(quán)限的學(xué)習(xí)后拱礁,會(huì)有進(jìn)一步認(rèn)識(shí)) 琢锋。
3.2、super訪問(wèn)普通成員
在子類的任意位置呢灶,均可以使用super.屬性名或者super.方法名()的方式訪問(wèn)父類空間的非私有成員吴超。
代碼示例:
/*
* 自定義類型Person 類
*
* name? age
*
* 吃? 睡
*/
public abstract class Person {
private String name;
int age;
//定義無(wú)參構(gòu)造方法
public Person(){
//方法邏輯
System.out.println("我是Person的無(wú)參構(gòu)造");
}
//定義帶參構(gòu)造一般都是為了給成員變量賦值
public Person(String name ,int age){
System.out.println("我是Person帶參構(gòu)造給成員變量賦值");
this.name = name;
this.age = age;
}
private void eat(){
System.out.println("吃");
}
public void sleep(){
System.out.println("睡");
}
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;
}
}
/*
* 自定義Studnet繼承Person類
*
* super訪問(wèn)父類構(gòu)造方法
*? 在子類的所有構(gòu)造方法的第一行 都默認(rèn)調(diào)用了父類的無(wú)參構(gòu)造? super()?
*? 我們通過(guò)super(參數(shù))調(diào)用父類的帶參構(gòu)造 給父類的成員變量賦值
* super訪問(wèn)普通成員
*? 在子類的任意位置,均可以使用super.屬性名或者super.方法名()的方式訪問(wèn)父類空間的非私有成員鸯乃。
*
*/
public class Student extends Person{
private String number;
/*
* 無(wú)參構(gòu)造
*/
public Student() {
super();
System.out.println("Studnet的無(wú)參構(gòu)造");
}
//帶參構(gòu)造
public Student(String number,String name,int age) {
super(name,age);
System.out.println("Studnet的帶參構(gòu)造");
this.number = number;
}
public void method(){
//super.屬性名可以訪問(wèn)父類的非私有成員變量
//System.out.println(super.name);
System.out.println(super.age);
//super.方法名()可以訪問(wèn)父類的非私有成員方法
//? super.eat();
super.sleep();
}
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
}
/*
* 測(cè)試有繼承關(guān)系的構(gòu)造方法
*/
public class Test {
public static void main(String[] args) {
//? Student s = new Student();
Student s2 = new Student("2016","柳巖",38);
System.out.println(s2.getNumber());
System.out.println(s2.getName());
System.out.println(s2.getAge());
}
}
3.3鲸阻、super調(diào)用父類構(gòu)造方法
在子類的每個(gè)構(gòu)造方法中,第一行具有默認(rèn)調(diào)用父類空參構(gòu)造代碼缨睡,即super().所以在每次創(chuàng)建子類對(duì)象時(shí)鸟悴,會(huì)先創(chuàng)建父類的構(gòu)造。
使用super(參數(shù))可以訪問(wèn)父類任意參數(shù)的構(gòu)造奖年,當(dāng)手動(dòng)調(diào)用父類任意的構(gòu)造方法后细诸,Java將不再提供默認(rèn)調(diào)用父類空參的構(gòu)造方法。
/*
* 自定義類型Person 類
*
* name? age
*
* 吃? 睡
*/
public abstract class Person {
private String name;
Private int age;
//定義無(wú)參構(gòu)造方法
public Person(){
//方法邏輯
System.out.println("我是Person的無(wú)參構(gòu)造");
}
//定義帶參構(gòu)造一般都是為了給成員變量賦值
public Person(String name ,int age){
System.out.println("我是Person帶參構(gòu)造給成員變量賦值");
this.name = name;
this.age = age;
}
Public void eat(){
System.out.println("吃");
}
public void sleep(){
System.out.println("睡");
}
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;
}
}
/*
* 自定義Studnet繼承Person類
*
* super訪問(wèn)父類構(gòu)造方法
*? 在子類的所有構(gòu)造方法的第一行 都默認(rèn)調(diào)用了父類的無(wú)參構(gòu)造? super()?
*? 我們通過(guò)super(參數(shù))調(diào)用父類的帶參構(gòu)造 給父類的成員變量賦值
* super訪問(wèn)普通成員
*? 在子類的任意位置陋守,均可以使用super.屬性名或者super.方法名()的方式訪問(wèn)父類空間的非私有成員震贵。
*
*/
public class Student extends Person{
private String number;
/*
* 無(wú)參構(gòu)造
*/
public Student() {
super();
System.out.println("Studnet的無(wú)參構(gòu)造");
}
//帶參構(gòu)造
public Student(String number,String name,int age) {
super(name,age);
System.out.println("Studnet的帶參構(gòu)造");
this.number = number;
}
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
}
/*
* 測(cè)試有繼承關(guān)系的構(gòu)造方法
*/
public class Test {
public static void main(String[] args) {
//? Student s = new Student();
Student s2 = new Student("2016","柳巖",38);
System.out.println(s2.getNumber());
System.out.println(s2.getName());
System.out.println(s2.getAge());
}
}
4鹏浅、this關(guān)鍵字
4.1、this關(guān)鍵字概念回顧
this代表本類一個(gè)對(duì)象的引用屏歹,當(dāng)創(chuàng)建了一個(gè)子類對(duì)象時(shí),子類自己的空間可以使用this訪問(wèn)到之碗。
4.2蝙眶、this調(diào)用普通成員
在子類的任意位置,均可以使用this.屬性名或者this.方法名()的方式訪問(wèn)子類自身空間的成員褪那。
4.3幽纷、this調(diào)用本類其他構(gòu)造
使用this(參數(shù))可以訪問(wèn)子類任意其他參數(shù)的構(gòu)造方法,當(dāng)手動(dòng)調(diào)用子類任意的構(gòu)造方法后博敬,Java將不再提供默認(rèn)調(diào)用父類空參的構(gòu)造方法友浸。
this調(diào)用構(gòu)造方法與super調(diào)用構(gòu)造方法不能同時(shí)出現(xiàn)。
無(wú)論以哪種方式完成構(gòu)造方法的定義偏窝,均會(huì)先創(chuàng)建父類對(duì)象收恢,再創(chuàng)建子類對(duì)象。
package cn.javahelp3;
/*
* 自定義類型Person 類
*
* name? age
*
* 吃? 睡
*/
public abstract class Person {
private String name;
int age;
//定義無(wú)參構(gòu)造方法
public Person(){
//方法邏輯
System.out.println("我是Person的無(wú)參構(gòu)造");
}
//定義帶參構(gòu)造一般都是為了給成員變量賦值
public Person(String name ,int age){
System.out.println("我是Person帶參構(gòu)造給成員變量賦值");
this.name = name;
this.age = age;
}
private void eat(){
System.out.println("吃");
}
public void sleep(){
System.out.println("睡");
}
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;
}
}
package cn.javahelp3;
/*
* 自定義教師
*
* this
*
* this調(diào)用本類其他構(gòu)造
*? this(參數(shù))可以調(diào)用本來(lái)當(dāng)中其他構(gòu)造方法
*
* this訪問(wèn)本來(lái)的普通成員
*? 在子類的任意位置祭往,均可以使用this.屬性名或者this.方法名()的方式訪問(wèn)子類自身空間的成員伦意。
*
*/
public class Teacher extends Person{
//id
private String id;
public Teacher() {
//this(參數(shù))可以調(diào)用本來(lái)當(dāng)中其他構(gòu)造方法
this("90213");
}
public Teacher(String name, int age,String id) {
super(name, age);
this.id = id;
}
public Teacher(String id){
super();
this.id = id;
}
public void method(){
//在子類的任意位置,均可以使用this.屬性名或者this.方法名()的方式訪問(wèn)子類自身空間的成員硼补。
System.err.println(this.id);
this.teach();
}
public void teach(){
System.out.println("教學(xué)生的方法");
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
}
5驮肉、this與super的使用對(duì)比及注意事項(xiàng)
(1)訪問(wèn)子類區(qū)域的成員使用this,訪問(wèn)父類區(qū)域的成員使用super已骇。
this:
(2)訪問(wèn)本類對(duì)象成員變量:this.變量名
(3)調(diào)用本類普通方法:this.方法名(參數(shù))
(4)本類構(gòu)造方法調(diào)用本類其他構(gòu)造:本類構(gòu)造方法第一行this(參數(shù))
super:
(5)訪問(wèn)本類對(duì)象當(dāng)中的父類對(duì)象成員變量:super.變量名
(6)調(diào)用本類對(duì)象當(dāng)中的父類普通方法:super.方法名()
(7)本類構(gòu)造方法調(diào)用父類構(gòu)造:本類構(gòu)造方法第一行super(參數(shù))
變量訪問(wèn)的就近原則:
(8)當(dāng)多個(gè)位置出現(xiàn)相同名稱的變量時(shí)离钝,訪問(wèn)時(shí)會(huì)根據(jù)就近原則依次訪問(wèn)其先后順序?yàn)椋?/p>
局部位置>本類成員位置>父類成員位置 >父類的父類成員位置 …
package cn.javahelp4;
/*
* 變量的就近訪問(wèn)原則
*/
public class Fu {
String name = "父類名字";
}
package cn.javahelp4;
public class Zi extends Fu {
String name = "子類名字";
public void method(){
String name = "局部名字";
System.out.println(name);
System.out.println(this.name);
System.out.println(super.name);
}
}
package cn.javahelp4;
/*
* 當(dāng)多個(gè)位置出現(xiàn)相同名稱的變量時(shí),訪問(wèn)時(shí)會(huì)根據(jù)就近原則依次訪問(wèn)褪储。其先后順序?yàn)椋?/p>
局部位置 >? 本類成員位置 >? 父類成員位置? >? 父類的父類成員位置? …
*/
public class Test {
public static void main(String[] args) {
Zi zi = new Zi();
zi.method();
}
}
注意:
this與super在調(diào)用構(gòu)造方法時(shí)卵渴,均必須在第一行,只能調(diào)用其中的一個(gè)乱豆。
父類多個(gè)構(gòu)造奖恰,子類調(diào)用父類某個(gè)參數(shù)的構(gòu)造時(shí),必須保證父類有這個(gè)構(gòu)造宛裕,否則報(bào)錯(cuò)瑟啃。
package cn.javahelp5;
/*
* 自定義Person類
*
*? name age
*/
public class Person {
private String name;
private int age;
public Person(){
}
public Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
public Person(int age){
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;
}
}
package cn.javahelp5;
/*
* 學(xué)生類
*
*this與super在調(diào)用構(gòu)造方法時(shí),均必須在第一行揩尸,只能調(diào)用其中的一個(gè)蛹屿。
* 父類多個(gè)構(gòu)造,子類調(diào)用父類某個(gè)參數(shù)的構(gòu)造時(shí)岩榆,必須保證父類有這個(gè)構(gòu)造错负,否則報(bào)錯(cuò)坟瓢。
*/
public class Student extends Person{
public Student() {
super();
}
public Student(String name, int age) {
super(name, age);
}
public Student(int age){
super(age);
}
}
6、對(duì)多態(tài)向上向下轉(zhuǎn)型的內(nèi)存解釋
向上轉(zhuǎn)型:
如圖所示犹撒,當(dāng)出現(xiàn)多態(tài)時(shí)折联,引用為Person類型,對(duì)象為Chinese對(duì)象识颊,此時(shí)诚镰,由于Chinese中包含了父類所有成員,所以可以訪問(wèn)父類非私有的一切祥款。對(duì)外表現(xiàn)的就”像個(gè)父類對(duì)象一樣”清笨。僅僅在調(diào)用方法時(shí),會(huì)調(diào)用子類重寫后的方法刃跛。
向下轉(zhuǎn)型:
當(dāng)出現(xiàn)多態(tài)后抠艾,父類Person引用指向子類對(duì)象,當(dāng)強(qiáng)轉(zhuǎn)為子類引用時(shí)桨昙,由于堆內(nèi)存當(dāng)中存儲(chǔ)的仍為子類對(duì)象检号,包含子類的一切成員。所以可以轉(zhuǎn)型成功绊率。
但是谨敛,如果沒(méi)有出現(xiàn)多態(tài),僅僅創(chuàng)建父類對(duì)象(如果父類不是抽象類的話)滤否,則為? ? 父類Person的引用指向Person的對(duì)象脸狸,沒(méi)有子類的對(duì)象。此時(shí)如果強(qiáng)轉(zhuǎn)為子類對(duì)象藐俺,則不包含子類的一些屬性與功能炊甲,所以強(qiáng)轉(zhuǎn)失敗。
思考:
當(dāng)子父類中有相同名稱的成員變量時(shí)欲芹,強(qiáng)轉(zhuǎn)前與強(qiáng)轉(zhuǎn)后訪問(wèn)的是相同的屬性值么卿啡?
代碼示例:
/*
* 變量的就近訪問(wèn)原則
*/
public class Fu {
String name = "父類名字";
}
package cn.javahelp4;
public class Zi extends Fu {
String name = "子類名字";
public void method(){
String name = "局部名字";
System.out.println(name);
System.out.println(this.name);
System.out.println(super.name);
}
}
public class Test1 {
public static void main(String[] args) {
Fu fu = new Zi();
System.out.println(fu.name);
Zi zi = (Zi)fu;
System.out.println(zi.name);
}
}