Java之super关键字详解

super

问题引入:

​ 从父类继承的非private成员,和子类新增的成员重名,如何在子类成员方法中区分两个成员?

答:

​ 借助super关键字可以实现区分!

具体用法:

  • super.数据成员,表示从父类继承的数据成员

  • super.成员方法(实参列表),表示调用从父类继承的成员方法

super表示子类对象中从父类继承的那部分(可看成一个父类对象)引用!

super内存结构图如下:
在这里插入图片描述

案例展示:

修改父类代码:

package com.briup.chap06.bean;

//提供父类
public class Animal {
	//对age进行显示初始化,其他代码不动
	public int age = 10;
 
    //...省略
}

修改子类代码:

package com.briup.chap06.bean;

//定义Dog子类 继承 Animal
public class Dog extends Animal {
	//子类新增数据成员并做显式初始化,成员名和从父类继承的一样
	private int age = 20;
	
	//新增方法,其形参名(局部变量)和数据成员名一样
	public void memberAccess(int age) {
		System.out.println("age: " + age);
		System.out.println("this.age: " + this.age);
		System.out.println("super.age: " + super.age);
	}
    
    //新增重载方法,其形参为空
    public void memberAccess() {
		System.out.println("age: " + age);
		System.out.println("this.age: " + this.age);
		System.out.println("super.age: " + super.age);
	}
	
    //其他代码不变,省略...
}

测试类:

package com.briup.chap06.test;

public class Test0203_AccessMember {
	//修改main方法如下
	public static void main(String[] args) {
		Dog d = new Dog();
		d.memberAccess(30);
		
		System.out.println("------------");
		
		d.memberAccess();
	}
}

运行效果:
在这里插入图片描述

在子类方法中访问变量,会遵循就近原则,具体如下:

  1. 先在子类局部范围中查找局部变量
  2. 再在子类中查找新增的成员变量
  3. 最后从父类继承的成员变量中查找

如果一定要使用从父类继承的成员,可以通过super关键字,进行区分。

super 总结:

  • super 关键字的用法和 this 关键字的用法相似

  • this:代表本类对象的引用

  • super:代表父类存储空间的标识(可以理解为父类对象引用)

构造方法

思考:如何给子类对象进行初始化?

子类对象的数据成员包含两部分:继承部分,新增部分

  • 对新增部分数据成员初始化,子类构造方法中直接this.新增数据成员 = 值;即可

  • 对继承部分数据成员初始化

    • 子类构造方法中直接super.继承数据成员 = 值;

      Bug:父类中数据成员如果private修饰,则子类中没有权限直接访问

    • 子类构造方法中采用super.setXxx(值);对继承部分数据成员进行初始化

      Bug:过于繁琐,如果从父类继承的成员很多,要写很多set方法

子类对象的初始化(构造方法中),要借助父类的构造方法,对父类部分成员进行初始化

  • 子类构造方法通过super关键字调用父类构造方法

    格式:super(实际参数列表);

  • 子类构造方法前,会优先找到父类构造方法调用,对父类继承部分成员进行初始化

  • 父类部分初始化完成后,再执行子类构造方法代码

  • 如果子类构造方法中没有显式通过super调用父类构造方法,则系统会默认调用super()

案例展示:

package com.briup.chap06.test;

//定义父类
class Fu {
	//1个私有成员
	private int f;
	
	//2个构造方法
	public Fu() {
		System.out.println("in Fu() ...");
	}
	
	public Fu(int f) {
		System.out.println("in Fu(int) ...");
		
		this.f = f;
	}

	//对应的get|set方法
	public int getF() {
		return f;
	}

	public void setF(int f) {
		this.f = f;
	}
}

//定义子类
class Zi extends Fu {
	//新增1个数据成员
	private int z;
	
	//子类构造方法
	public Zi() {
		//如果不显式调用super,则默认调用父类无参构造器
		//super();
		System.out.println("in Zi() ...");
	}
	
	public Zi(int z) {
		super(10);
		System.out.println("in Zi(int) ...");
		this.z = z;
	} 
	
	public Zi(int f, int z) {
		//下面这行注释的代码,放开则编译报错
		//System.out.println("in Zi(int,int) ...");
		
		//super调用,必须为子类构造方法的第一行有效代码
		super(f);
		System.out.println("in Zi(int,int) ...");
		
		this.z = z;
	}
	
	// 新增方法
	public void disp() {
		//借助super可以直接访问父类继承部分的成员
		System.out.println("super.f: " + super.getF());
		//借助this,会先去找子类新增getF(),如果找不到,再去父类继承部分查找
		System.out.println("this.f: " + this.getF());
		System.out.println("Zi.z: " + z);
	}
}

public class Test04_Init {
	public static void main(String[] args) {
		Zi z1 = new Zi();
		z1.disp();
		
		System.out.println("---------------");
		
		Zi z2 = new Zi(20);
		z2.disp();
		
		System.out.println("---------------");
		
		Zi z3 = new Zi(100,200);
		z3.disp();
	}
}

运行效果:
在这里插入图片描述

注意1:子类构造方法中如果显式调用super(实参列表),则该代码必须为第一行有效代码!

注意2:子类构造方法中显式调用的super(实参列表),父类中必须提供,否则编译报错!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值