目录
我们知道,子类既可以继承父类的方法,同时也可以重写具有自己特色的方法,那么,该如何判断在子类中调用的是方法是继承自父类还是自己重写的方法呢
通过代码测试,我们可以写定义一个动物类Animal及它的子类,并在其子类中重写父类的相关方法
既在父类和子类中都定义run()方法,最后调用,看是哪个类中的run()方法被实现。
父类Animal:
package com.imooc.animal;
//写公共的属性
public class Animal {
private String name;
private int month;
private String species;
public Animal() { //无参构造
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getMonth() {
return month;
}
public setMonth(int month) {
this.month = month;
}
public String getSpecies() {
return species;
}
public void setSpecies(String species) {
this.species = species;
}
//定义run方法
public void run() {
System.out.println(this.getName()+"是一只"+this.getSpecies()+",它正在欢快的奔跑");
}
}
然后我们一样在子类Cat 中同样写一个run()方法,然后将run()方法写入eat()方法里,在Test类中调用eat()方法
package com.imooc.animal;
public class Cat extends Animal{
private int weight;
public Cat() { //无参构造
}
public int getWeight() {
return weight;
}
public void setWeight(int weight) {
this.weight = weight;
}
public void eat() {
run(); //调用的哪个run()
System.out.println(this.getName()+"爱吃小鱼干");
}
public void run() { //子类中的run方法
System.out.println(this.getName()+"喜欢在草坪玩耍");
}
}
在测试类Test中调用eat()方法(eat()方法下包含的run()方法,所以调用eat())
package com.imooc.test;
import com.imooc.animal.Cat;
public class Test{
public static void main(String[] args) {
Cat one= new Cat();//创建Cat类对象并为其分配内存
one.setName("喵喵");
one.setSpecies("波斯猫");
one.eat(); //调用eat(),eat()方法下再实现run(),看被调用的是Animal父类中的run()方法还是Cat子类中的run()方法
}
}
总结:代码运行后显示测试中的run()方法是调用了Cat子类中的run()方法
关键字Super的使用
假定我们就想实现Animal父类下的run()方法呢?这里就要用到Super关键字
Super:父类对象的引用
在上述代码中实现:
super.run();
将关键字super加入到我们的Cat测试类中的被调用的run()方法前
改写后的Cat类
package com.imooc.animal;
public class Cat extends Animal{
private int weight;
public Cat() { //无参构造
}
public int getWeight() {
return weight;
}
public void setWeight(int weight) {
this.weight = weight;
}
public void eat() {
super.run(); //加入引用父类的关键字
System.out.println(this.getName()+"爱吃小鱼干");
}
public void run() { //子类中的run方法
System.out.println(this.getName()+"喜欢在草坪玩耍");
}
}
运行结果:
总结:此时调用run()方法前加入关键字super(父类对象的引用),代码实现的是父类Animal类下的run()方法,而不是子类中的run()方法,这就实现了super关键字的作用
同样,在满足继承关系的子类当中,我们也可以通过Super这个关键字来访问父类的指定成员
父类的构造方法能否被继承
在子类Cat当中,我们可以直接调用父类中的run()方法,并且无报错
父类中的run()方法
在Cat中调用:
但是如果在子类Cat调用Animal父类中的animal( )构造方法则会直接报错
父类中的Animal无参构造方法
在Cat中调用:
public static int st2=23;
根据这一结论,我们得出父类的构造方法不允许被子类继承,也就不允许被重写
继承的初始化顺序
1.我们在Animal类中加两条静态成员,用private,public两个不同的访问修饰符限定一下
private static int st1=22;
public static int st2=23;
再分别创造一个静态代码块和构造代码块
static{ //静态代码块
System.out.println("我是静态代码块");
}
{ //构造代码块
System.out.println("我是构造代码块");
}
在父类的无参构造中也加入输出语句
public Animal ( ) {
System.out.println("我是父类的无参构造方法");
}
完整代码:
package com.imooc.animal;
//写公共的属性
public class Animal {
private String name;
private int month;
private String species;
private static int st1=22;
public static int st2=23;
static{ //静态代码块
System.out.println("我是静态代码块");
}
{ //构造代码块
System.out.println("我是构造代码块");
}
public Animal() { //无参构造
System.out.println("我是父类的无参构造方法");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getMonth() {
return month;
}
public void setMonth(int month) {
this.month = month;
}
public String getSpecies() {
return species;
}
public void setSpecies(String species) {
this.species = species;
}
//定义run方法
public void run() {
System.out.println(this.getName()+"是一只"+this.getSpecies()+",它正在欢快的奔跑");
}
}
2.同样的把Cat子类中也加入相应的代码块和访问修饰符
package com.imooc.animal;
public class Cat extends Animal{
private int weight;
public static int st2=23;
static{ //静态代码块
System.out.println("我是静态代码块");
}
{ //构造代码块
System.out.println("我是构造代码块");
}
public Cat() { //无参构造
System.out.println("我是子类的无参构造方法");
}
public int getWeight() {
return weight;
}
public void setWeight(int weight) {
this.weight = weight;
}
public void eat() {
super.run();
animal();
System.out.println(this.getName()+"爱吃小鱼干");
}
public void run() {
System.out.println(this.getName()+"喜欢在草坪玩耍");
}
}
新建一个Test类:
package com.imooc.test;
import com.imooc.animal.Cat;
public class Test{
public static void main(String[] args) {
Cat one = new Cat();
System.out.println(one.temp);
}
}
结果显示:
所以在Java 中,当创建一个子类对象时,初始化的顺序如下:
- 首先,会初始化父类的静态成员和静态代码块(按照它们在代码中的出现顺序)。
- 然后,初始化子类的静态成员和静态代码块(同样按照出现顺序)。
- 接下来,父类的非静态成员和非静态代码块会被初始化(按照声明顺序)。
- 之后,父类的构造函数被调用。
- 最后,子类的非静态成员和非静态代码块按照声明顺序初始化,子类的构造函数被调用。
这样的初始化顺序确保了在子类对象的创建过程中,父类的相关部分先正确初始化,然后再完成子类的初始化。