从屌丝到架构师的飞越(面向对象篇)-继承中的构造方法

一、介绍

在继承中,我们子类继承了父类,并没有继承他的构造方法,所以我们要了解的是子类与父类的构造方法的处理。

二、知识点介绍

1、继承关系内存解释

2、父类对象优于子类对象产生

3、super关键字

4、this关键字

5、super与this比较

6、对多态向上向下转型的内存解释

三、上课视频对应说明文档

1、继承关系内存解释

实际上在面向对象第一天的讲解当中,我们对内存方面做了一些隐瞒。因为除了Object类,所有的类都是有父类的。但是我们在考虑内存图时忽略了这点,现在,我们来简单描述加入了子父类关系后的对象内存图。

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

}

//对address的get/set

}

//定义测试类,使用子类创建对象

public class Test{

Chinese c = new Chinese(“AngelaBaby”,18,”北京海淀区上地7街晋福公寓”);

}

对象内存图

代码示例:

/*

* 自定义类型Person 类

*

* name  age

*

* 吃  睡

*/

public abstract class Person {

private String name;

int age;

//定义无参构造方法

public Person(){

//方法逻辑

System.out.println("我是Person的无参构造");

}

//定义带参构造一般都是为了给成员变量赋值

public Person(String name ,int age){

System.out.println("我是Person带参构造给成员变量赋值");

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;

/*

* 无参构造

*/

public Student() {

System.out.println("Studnet的无参构造");

}

//带参构造

public Student(String number,String name,int age) {

System.out.println("Studnet的带参构造");

this.number = number;

}

public String getNumber() {

return number;

}

public void setNumber(String number) {

this.number = number;

}

}

/*

* 测试有继承关系的构造方法

*/

public class Test {

public static void main(String[] args) {

//Student s = new Student();

Student s2 = new Student("2016");

}

2、父类对象优于子类对象产生

在每次创建子类对象时,我们均会先创建父类对象,再创建其子类对象本身。目的在于子类对象中包含了其对应的父类对象,便可以包含其父类对象的成员,如果父类成员非private修饰,则子类可以随意使用父类成员。

反之,如果没有先创建父类对象就使用了子类对象,则子类无法使用父类的成员。抽象类包含构造方法的原因就在于其仅仅是为了给成员变量赋值,供子类使用。

这里我们需要注意的是,内存当中实际是存在抽象类的对象空间的,我们无法直接创建抽象类对象,但是子类可以,在子类的内存空间中包括了这个抽象父类对象。

3、super关键字

3.1、super关键字概念

super代表本类对象中包含的父类对象空间的引用。

当有了继承关系后,创建一个子类对象时,会先在子类中创建其父类对象,则子类对象包含了父类的所有方法与属性,而其非私有的方法一般都可以访问 (在完成访问权限的学习后,会有进一步认识) 。

3.2、super访问普通成员

在子类的任意位置,均可以使用super.属性名或者super.方法名()的方式访问父类空间的非私有成员。

代码示例:

/*

* 自定义类型Person 类

*

* name  age

*

* 吃  睡

*/

public abstract class Person {

private String name;

int age;

//定义无参构造方法

public Person(){

//方法逻辑

System.out.println("我是Person的无参构造");

}

//定义带参构造一般都是为了给成员变量赋值

public Person(String name ,int age){

System.out.println("我是Person带参构造给成员变量赋值");

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访问父类构造方法

*  在子类的所有构造方法的第一行 都默认调用了父类的无参构造  super() 

*  我们通过super(参数)调用父类的带参构造 给父类的成员变量赋值

* super访问普通成员

*  在子类的任意位置,均可以使用super.属性名或者super.方法名()的方式访问父类空间的非私有成员。

*

*/

public class Student extends Person{

private String number;

/*

* 无参构造

*/

public Student() {

super();

System.out.println("Studnet的无参构造");

}

//带参构造

public Student(String number,String name,int age) {

super(name,age);

System.out.println("Studnet的带参构造");

this.number = number;

}

public void method(){

//super.属性名可以访问父类的非私有成员变量

//System.out.println(super.name);

System.out.println(super.age);

//super.方法名()可以访问父类的非私有成员方法

//  super.eat();

super.sleep();

}

public String getNumber() {

return number;

}

public void setNumber(String number) {

this.number = number;

}

}

/*

* 测试有继承关系的构造方法

*/

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调用父类构造方法

在子类的每个构造方法中,第一行具有默认调用父类空参构造代码,即super().所以在每次创建子类对象时,会先创建父类的构造。

使用super(参数)可以访问父类任意参数的构造,当手动调用父类任意的构造方法后,Java将不再提供默认调用父类空参的构造方法。

/*

* 自定义类型Person 类

*

* name  age

*

* 吃  睡

*/

public abstract class Person {

private String name;

Private int age;

//定义无参构造方法

public Person(){

//方法逻辑

System.out.println("我是Person的无参构造");

}

//定义带参构造一般都是为了给成员变量赋值

public Person(String name ,int age){

System.out.println("我是Person带参构造给成员变量赋值");

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访问父类构造方法

*  在子类的所有构造方法的第一行 都默认调用了父类的无参构造  super() 

*  我们通过super(参数)调用父类的带参构造 给父类的成员变量赋值

* super访问普通成员

*  在子类的任意位置,均可以使用super.属性名或者super.方法名()的方式访问父类空间的非私有成员。

*

*/

public class Student extends Person{

private String number;

/*

* 无参构造

*/

public Student() {

super();

System.out.println("Studnet的无参构造");

}

//带参构造

public Student(String number,String name,int age) {

super(name,age);

System.out.println("Studnet的带参构造");

this.number = number;

}

public String getNumber() {

return number;

}

public void setNumber(String number) {

this.number = number;

}

}

/*

* 测试有继承关系的构造方法

*/

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关键字

4.1、this关键字概念回顾

this代表本类一个对象的引用,当创建了一个子类对象时,子类自己的空间可以使用this访问到。

4.2、this调用普通成员

在子类的任意位置,均可以使用this.属性名或者this.方法名()的方式访问子类自身空间的成员。

4.3、this调用本类其他构造

使用this(参数)可以访问子类任意其他参数的构造方法,当手动调用子类任意的构造方法后,Java将不再提供默认调用父类空参的构造方法。

this调用构造方法与super调用构造方法不能同时出现。

无论以哪种方式完成构造方法的定义,均会先创建父类对象,再创建子类对象。

package cn.javahelp3;

/*

* 自定义类型Person 类

*

* name  age

*

* 吃  睡

*/

public abstract class Person {

private String name;

int age;

//定义无参构造方法

public Person(){

//方法逻辑

System.out.println("我是Person的无参构造");

}

//定义带参构造一般都是为了给成员变量赋值

public Person(String name ,int age){

System.out.println("我是Person带参构造给成员变量赋值");

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调用本类其他构造

*  this(参数)可以调用本来当中其他构造方法

*

* this访问本来的普通成员

*  在子类的任意位置,均可以使用this.属性名或者this.方法名()的方式访问子类自身空间的成员。

*

*/

public class Teacher extends Person{

//id

private String id;

public Teacher() {

//this(参数)可以调用本来当中其他构造方法

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.方法名()的方式访问子类自身空间的成员。

System.err.println(this.id);

this.teach();

}

public void teach(){

System.out.println("教学生的方法");

}

public String getId() {

return id;

}

public void setId(String id) {

this.id = id;

}

}

5、this与super的使用对比及注意事项

(1)访问子类区域的成员使用this,访问父类区域的成员使用super。

this:

(2)访问本类对象成员变量:this.变量名

(3)调用本类普通方法:this.方法名(参数)

(4)本类构造方法调用本类其他构造:本类构造方法第一行this(参数)

super:

(5)访问本类对象当中的父类对象成员变量:super.变量名

(6)调用本类对象当中的父类普通方法:super.方法名()

(7)本类构造方法调用父类构造:本类构造方法第一行super(参数)

变量访问的就近原则:

(8)当多个位置出现相同名称的变量时,访问时会根据就近原则依次访问其先后顺序为:

局部位置>本类成员位置>父类成员位置 >父类的父类成员位置 …

package cn.javahelp4;

/*

* 变量的就近访问原则

*/

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;

/*

* 当多个位置出现相同名称的变量时,访问时会根据就近原则依次访问。其先后顺序为:

局部位置 >  本类成员位置 >  父类成员位置  >  父类的父类成员位置  …

*/

public class Test {

public static void main(String[] args) {

Zi zi = new Zi();

zi.method();

}

}

注意:

this与super在调用构造方法时,均必须在第一行,只能调用其中的一个。

父类多个构造,子类调用父类某个参数的构造时,必须保证父类有这个构造,否则报错。

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;

/*

* 学生类

*

*this与super在调用构造方法时,均必须在第一行,只能调用其中的一个。

* 父类多个构造,子类调用父类某个参数的构造时,必须保证父类有这个构造,否则报错。

*/

public class Student extends Person{

public Student() {

super();

}

public Student(String name, int age) {

super(name, age);

}

public Student(int age){

super(age);

}

}

6、对多态向上向下转型的内存解释

向上转型:

如图所示,当出现多态时,引用为Person类型,对象为Chinese对象,此时,由于Chinese中包含了父类所有成员,所以可以访问父类非私有的一切。对外表现的就”像个父类对象一样”。仅仅在调用方法时,会调用子类重写后的方法。

向下转型:

当出现多态后,父类Person引用指向子类对象,当强转为子类引用时,由于堆内存当中存储的仍为子类对象,包含子类的一切成员。所以可以转型成功。

但是,如果没有出现多态,仅仅创建父类对象(如果父类不是抽象类的话),则为    父类Person的引用指向Person的对象,没有子类的对象。此时如果强转为子类对象,则不包含子类的一些属性与功能,所以强转失败。

思考:

当子父类中有相同名称的成员变量时,强转前与强转后访问的是相同的属性值么?

代码示例:

/*

* 变量的就近访问原则

*/

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

}

}

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,445评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,889评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,047评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,760评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,745评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,638评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,011评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,669评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,923评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,655评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,740评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,406评论 4 320
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,995评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,961评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,023评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,483评论 2 342

推荐阅读更多精彩内容