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

一、介绍

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

二、知识点介绍

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街晋福公寓”);

}

对象内存图

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

代码示例:

/*

* 自定义类型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、对多态向上向下转型的内存解释

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

向上转型:

如图所示,当出现多态时,引用为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);

}

}

你可能感兴趣的:(从屌丝到架构师的飞越(面向对象篇)-继承中的构造方法)