欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Java中super关键字的详细分析

程序员文章站 2023-03-07 17:31:13
super关键字的使用:(1)super是一个关键字;(2)super和this很类似,我们对比着学习。先复习一下this关键字的使用。this关键字:this能出现在实例方法和构造方法中;this的语法是“this.”和“this()”;this不能出现在静态方法中;this大部分情况下是可以省略的;this.什么时候不能省略呢?在区*部变量和实例变量时不能省略。例如:Public void setName(String name){this.name = name;}...

super关键字的使用:
(1)super是一个关键字;
(2)super和this很类似,我们对比着学习。

先复习一下this关键字的使用。

this关键字:

  1. this能出现在实例方法和构造方法中;
  2. this的语法是“this.”和“this()”;
  3. this不能出现在静态方法中;
  4. this大部分情况下是可以省略的;
  5. this.什么时候不能省略呢?在区*部变量和实例变量时不能省略。例如:
Public void setName(String name){
	this.name = name;
}
  1. this()只能出现在构造方法的第一行,通过当前的构造方法去调用“本类”中的对应的构造方法,目的是:代码复用。

super关键字:

  1. super能出现在实例方法和构造方法中;

  2. super的语法是“super.”和“super()”;

  3. super不能出现在静态方法中;

  4. super大部分情况下是可以省略的;

  5. super.什么时候不能省略呢?
        别急,我们想一下this指向的是什么,是当前对象自己。super和this类似,它指向了当前对象自己的父类型特征(也就是继承过来的那些东西)。

        super和this区别是:this可以看做一个引用变量,保存了改对象的地址,而super不能看做变量,因为super代表的是父类型特征,是一大堆继承过来的东西,总不能说super保存的是这一大堆东西的内存地址吧,显然不合适。通过下面的打印语句也知道this是变量,super不是:

System.out.println(this);  //输出this.toString()的值
System.out,println(super);  //编译报错

        当在子类对象中,子类想访问父类的东西,可以使用“super.”的方式访问。例如:方法覆盖后,子类内部虽然重写了父类的方法,但子类也想使用一下父类的被覆盖的方法,此时可以使用“super.”的方式。当子类中出现和父类一样的属性或者方法,此时,你要想去调用继承过来的那个属性或者方法,此时“super.”不能省略。

        总结:“this.”是一个实例对象内部为了区分实例变量和局部变量,而“super.”是一个实例对象为了区分是子类的成员还是父类的成员。父类有,子类也有,子类想访问父类的,“super.”不能省略。

  1. super()只能出现在构造方法的第一行,通过当前的构造方法去调用“父类”中的对应的构造方法,目的是:创建子类对象时,先初始化父类型特征。用通俗的话来讲,要想有儿子,得先有父亲。

没理解不要紧,我们先看下面代码:
写两个类,Animal和Cat,Cat继承Animal。

//父类,Animal类
class Animal {
	//构造函数
	public Animal() {
		System.out.println("Animal类的无参数构造函数执行");
	}
}

//子类,Cat类
class Cat extends Animal{
	//构造函数
	public Cat() {
		System.out.println("Cat类的无参数构造函数执行");
	}
}

执行下面一行代码:

Cat c1 = new Cat(); 

运行输出结果为:
    Animal类的无参数构造函数执行
    Cat类的无参数构造函数执行

我们发现实例化一个子类的对象,也就是调用了子类的构造方法,为什么父类的无参数构造方法也执行了,并在子类构造方法执行之前就已经执行了父类的无参数构造方法,好奇怪。

刚刚在上面的super关键字的使用第6点,我已经说了,super()和this()方法一样,都只能在构造方法的第一行出现。我们猜想,难道子类的构造方法第一行有一个隐形的super()方法?答案是肯定的。

我们把子类的构造方法的第一行给它加上super():

//子类,Cat类
class Cat extends Animal{
	//构造函数
	public Cat() {
		super();
		System.out.println("Cat类的无参数构造函数执行");
	}
}

再执行下面代码:

Cat c1 = new Cat(); 

运行输出结果为:
    Animal类的无参数构造函数执行
    Cat类的无参数构造函数执行

和刚才的子类构造方法没加super()是一样的。

所以说当子类的构造方法内第一行没有出现“super()”时,系统会默认给它加上无参数的"super()"方法,为了养成良好的习惯,当子类构造方法的第一行没有“this()”和“super()”方法时,我们手动给它第一行写上默认的"super()"方法。

阅读仔细的人会发现,为什么是没有“this()和super()”就写上“super()”?有“this()”就不能写上“super()”吗?那我问你,当构造方法第一行有"this()"时,你还能手动添加“super()”吗?显然不行,因为“this()”也只能出现在第一行,你不能在它前面写任何代码。所以我们又得出一个结论:构造方法中“this()”和“super()”不能同时出现,也就是“this()”和“super()”都只能出现在构造方法的第一行。

上面谈的都是无参数的“super”方法,我们也可以在构造方法的第一行使用有参数的“super(父类构造函数的参数列表)”,但值得注意的是,当子类构造方法执行有参数的“super(参数列表)”方法,你得确保父类中也有对应的有参数构造方法,不然会编译报错。同样我要提醒一下,当子类构造方法的第一行执行super()无参数方法,那么父类中一定要有无参数构造方法,有的人可能会在父类中写了有参数的构造方法,却忽略了写无参数构造方法,那么在子类构造方法内就会报错,因为当你在一个类中写了有参数的构造方法时,无参数构造方法就会不存在,你需要自己补上无参数的构造方法,这是一个良好的编程习惯。

无论你子类构造方法有没有“this()”和“super()”方法,实例化子类对象一定一定会执行对应的父类构造方法,即不管实例化了一个怎样的孩子,它一定会先实例化一个对应的父亲。

下面给道例题看是否你是真的懂了this()和super()方法:

public class MyTest {
	
	public static void main(String[] args) {
		new Cat(); 
	}
}

//父类,Animal类
class Animal {
	//构造函数
	public Animal() {
		super();
		System.out.println("1:Animal类的无参数构造函数执行");
	}
	public Animal(int i) {
		super();
		System.out.println("2:Animal类的有int参数构造函数执行");
	}
}

//子类,Cat类
class Cat extends Animal{
	//构造函数
	public Cat() {
		this("");
		System.out.println("3:Cat类的无参数构造函数执行");
	}
	public Cat(String str) {
		super(5);
		System.out.println("4:Cat类的有String参数构造函数执行");
	}
}

输出结果为:
2:Animal类的有int参数构造函数执行
4:Cat类的有String参数构造函数执行
3:Cat类的无参数构造函数执行

我们又可以得出一个结论:不管你创建什么对象,Object对象的无参数构造方法一定会先执行。

说了这么多,super()到底什么时候使用?来看下面代码:

public class MyTest {
	
	public static void main(String[] args) {
		Cat c1 = new Cat(3); 
		System.out.println("名字:" + c1.getName() + ",年龄:" + c1.getAge());
	}
}

//父类,Animal类
class Animal {
	//私有属性:名字
	private String name;
	
	//setter and getter
	public void setName(String name) {
		this.name = name;
	}
	public String getName() {
		return name;
	}
	
	//构造函数
	public Animal() {
		
	}
	public Animal(String name) {
		this.name = name;
	}
}

//子类,Cat类
class Cat extends Animal{
	//私有字段:年龄
	private int age;
	
	//setter and getter
	public void setAge(int age) {
		this.age = age;
	}
	public int getAge() {
		return age;
	}
	
	//构造函数
	public Cat() {
		
	}
	public Cat(int age) {
		this.age = age;
	}
}

输出结果:名字:null,年龄:3

我们也知道,没有给c1的name赋值嘛,当然为默认值null啦。
确实如此,所以我们给Cat加一个构造方法,给name和age都赋值。
如下:

public Cat(String name, int age) {
	this.name = name; //报错
	this.age = age
}

显然这样做是会报错的,因为name已经被父类封装成private的了,不能直接访问,可能有的人会这样做:

public Cat(String name, int age) {
	setName(name);
	this.age = age;
}

显然这样做的确可以做到给父类的name赋值,但这样做是不建议的,我们在构造方法中通常只调用构造方法,不会去调用实例方法,况且当不止一个变量时,用set方法时,我们就要调用好多个实例方法去完成赋值。这时候为什么不考虑使用super()方法呢?如下:

public Cat(String name, int age) {
	super(name);
	this.age = age;
}

这样就显得文雅,美观多了。

总结:

  1. this和super一样,都是个引用变量;
  2. this指向当前对象自己,super指向当前对象的父类型特征,故this的东西比super多,也就是super是this的一部分;
  3. this()和super()都只能出现在构造方法的第一行,故this()和super()方法不能共存,当一个类的构造方法第一行中没有this(),也没有super(),系统默认有super()方法;
  4. this()是构造方法中调用本类其他的构造方法,super()是构造方法中去调用自己父类的构造方法。

本文地址:https://blog.csdn.net/pipizhen_/article/details/107165618