Java-继承-定义Student类继承于Person类

我们书接上回:这一章,我们进入"继承"。

先来了解题目有关继承的需求:(本题是为知识服务,也可用于练手)

题目:

已有一个类Person类,代码如下:

Person类定义:

class Person {
    private String name;

    public Person(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }
    //做自我介绍
    public void doSelfIntroduction(){
        System.out.println("My name is "+name);
    }
}

现要求定义一个类Student继承于Person类,Student类的要求如下:

  1. 新增一个成员变量 :stuID 表示学生的学号;
  2. 一个带参数构造器,初始化学生的姓名和学号;
  3. 重写父类的void doSelfIntroduction() 方法,改输出为:"My name is xxxx and my stuID is xxxx"
  4. 新增一个方法,void study(),该方法输出:"I am studying!"

Main类代码:

public class Main{
    public static void main(String[] args) {
        Person person = new Person("Tom");
        Scanner scanner = new Scanner(System.in);
        String name = scanner.next();
        String stuID = scanner.next();
        Person stu1 = new Student(name,stuID);
        person.doSelfIntroduction();
        stu1.doSelfIntroduction();
        Student stu2 = new Student(name,stuID);
        stu2.study();
    }
}

输入样例:

在这里给出一组输入。例如:

Jerry 121001

输出样例:

在这里给出相应的输出。例如:

My name is Tom
My name is Jerry and my stuID is 121001
I am studying!

 继承:

继承这个词,一般在语言学上:子承父业,继往开来;在生物学上也异曲同工:遗传与变异

其实,好巧不巧,java世界里面的继承也是如此道理。还记得java的核心是什么吗?类。那类在继承场景中自然而然扮演主人公——继承(java),是子类对父类属性和行为的继承

父类(superclass),子类(subclass)

继承的语法

class 子类名 extends 父类名
{
 //可以不再重复定义相同成员变量


}

子类继承父类时,需要在类定义时,使用extends+ 父类名,表示继承关系 

继承的表现

既然继承是子类对父类属性和行为的继承——那么子类一旦继承父类,就可以拥有父类的属性和方法。这个说法确实是对的。

我们开始对这句话进行各种假设,父类是单一的吗?在继承语法上,只能extends一个直接父类。但子类的间接父类可以有很多个。就好比,人只有一个亲生父亲,却也有父亲的父亲,父亲的父亲的父亲,爷爷的爷爷的爷爷...这些间接的父类的属性和行为,子类同样也可以继承。

俩个验证

我们用代码验证

子类只允许单一继承父类:

 上面代码,我们子类单一直接继承一个父类——假如我们尝试一次性直接继承两个父类

这样:

又或者是这样: 

 

发现结果都报错了

:Class cannot extend multiple classes,不能同时继承多个父类

故:确实子类只能单一继承一个父类

验证:子类可以继承直接父类、间接父类的属性和方法:

我们写一个主类,创建三个类,Son类继承Father类,Father类继承Grandpa类

可知,在这三类的继承关系上,Grandpa类位于最高地位。

public class Grandpa {
     String name;//属性1:姓名
     int workyear;//属性2:工作年限
     void work()//行为1:工作
     {
         System.out.println(name + "写唐诗");
     }
     void hobby()//行为2:爱好
     {
         System.out.println(name + "君子六艺");
     }
}
public class Father extends Grandpa{
}//直接继承,定义类里代码为空

我们在main里验证,倘若符合子类只要extends一个父类,就可以拥有父类的属性和方法,何谓"拥有",能在主方法能对属性进行调用、赋值,对方法进行调用。

public class Main {
    public static void main(String[] args) {
        Father father = new Father();
        father.name = "钱";//调用对象的属性并对其进行赋值
        father.work();//调用对象的实例方法:工作
        father.hobby();//调用对象的实例方法:爱好
    }

}

代码并没有报错,说明子类只要继承父类,即可拥有父类的属性和方法

那子类可否继承间接父类的属性和方法呢?

public class Son extends Father {
    
}//Son类只是继承Father类,并没有定义其他属性和方法
public class Father extends Grandpa{
}//直接继承,定义类里代码为空

 主类里面:

public class Main {
    public static void main(String[] args) {
        Son son = new Son();//对类实例化
        son.name = "孙";//同样对姓名属性赋值
        son.work();//调用方法
        son.hobby();//调用方法
    }
}

看看效果: 

 

 Son类除了继承Father类没写一行,Father类如上也只继承了Grandpa类,按理说Son继承Father类,应该没有一个属性和方法。但是如上面的代码,可见,Son也继承了Grandpa的属性和两个方法——"work" 和"hobby".

我们来看看运行结果:

public class Main {
    public static void main(String[] args) {
        Grandpa grandpa = new Grandpa();
        grandpa.name = "赵";
        grandpa.work();
        grandpa.hobby();//创建一个grandpa的对象
        Father father = new Father();
        father.name = "钱";
        father.work();
        father.hobby();//创建一个father的对象
        Son son = new Son();
        son.name = "孙";
        son.work();
        son.hobby();//创建一个son的对象
    }

}

 

三代可谓一脉相承,都会写唐诗和善君子六艺 。可是,这并不符合实际发展,子类为适应不断发展变化的环境和外界需求,对自身的行为和属性必须作出相应的变化和发展。

JAVA里面对这一子类进化需求,也作出回应:
1.子类可以添加父类所不具有的属性和方法

2.子类也可对继承过来的方法进行修改,但不能对属性进行修改。

再来俩个验证

1.子类可以添加父类所不具有的属性和方法

我们让Son适应时代需求,新添加一个行为和一个属性

public class Son extends Father {
    String[] career;//添加属性:所谓技多不压身
    void work2()//添加方法
    {
        System.out.println(name + "武功高强");
    }

}
public class Main {
    public static void main(String[] args) {
        Son son = new Son();
        son.name = "孙";
        son.career = new String[]{"诗人","侠客"};//意外发现对于属性是字符串数组初始化赋值: new String[]{};
        son.work();
        son.work2();
        son.hobby();
    }

}

我们在Son类添加一个新的属性和方法,在主方法里对Son 进行实例化,并对属性进行赋值和方法调用。代码没报错,可见验证假设成功

看看结果:

2.子类也可对继承过来的方法进行修改,但不能对属性进行修改。 

前半句,对继承过来的方法进行修改,我们又称——方法覆盖(Method Override)

在进行Override的时候,我们最好提前在上方加个注释:意为告诉JVM我们要对继承过来的方法进行覆盖重写了。

方法覆盖:

方法包括:

返回类型 方法名(参数列表)
{
   方法体
}//如果原方法还有public ,覆盖的方法也得原封不动写下来

进行方法覆盖时,为了让JVM明确我们覆盖的到底是哪个方法,返回类型和方法名(参数列表)即除了方法体可做改变,其余保持原样。(返回类型可以返回原方法的类型的子类型,该知识点涉及向上转型,咱们后面再聊) 

方法覆盖必须满足返回类型,方法名和参数列表与原方法一样。(now)

子类为了适应发展,创造出更多的属性和行为,还应该对继承下来的方法进行进化,发展出一套适合自身和外界需求的方法。——这也是传承的意义,不光为子类自身,更为整个类的发展

我们重写Father类和Son类方法work()

public class Father extends Grandpa{
    @Override
    void work()//继承并覆盖Grandpa的方法
    {
        System.out.println(name + "满腹经纶,学富五车");
    }

}
public class Son extends Father {
    
    @Override//继承间接父类的方法并进行覆盖
    void work()
    {
        System.out.println(name + "文能提笔安天下,武能上马定乾坤");
    }


}

主类代码进行调用:

public class Main {
    public static void main(String[] args) {
        Grandpa grandpa = new Grandpa();
        grandpa.name = "赵";
        grandpa.work();
        
        Father father = new Father();
        father.name = "钱";
        father.work();
        
        Son son = new Son();
        son.name = "孙";
        son.work();   
    }

}

对父类属性的修改:

JAVA本身并不提供子类“覆盖”父类成员变量的方法,子类仍然继承,但是可以不用表现,就如遗传时,基因都给子类,至于是否显现这个性状,就看子类是否愿意在主方法里面调用了。

小总结:

子类通过extends关键字,单一继承父类

子类继承直接父类和所有间接父类的属性和方法

子类可以添加新的属性和方法

子类可以改变父类的方法体

回到题目

先继承;

class Student extends Person
{}

 在子类里面添加属性:

class Student extends Person
{
  String stuID;
}

在子类写一个带参数构造器:

class Student extends Person
{
  String stuID;
}
public Student(String name,String stuID)
{
    this.name = name;//真的是这样赋值吗
    this.stuID = stuID;

}//带参数构造器

我们发现报错了

 父类里面的name成员是private,子类不能公开访问,那子类拥有这个属性吗?答案是有的。但是不能公开访问,需要其他方式进行访问。

我们再看父类代码,发现父类的构造器是公开的:父类是这个属性的创始者,对于这个属性虽然是私有的,子类蛮干是无法访问的。但是父类也为我们公开了访问和使用的方法,扑面而来的哲学气息:授人以鱼不如授人以渔。

鱼,父类已经暗暗给你,不过需要你学会如何渔。

super关键字

还记得父类的英文名吗?superclass,super关键字就是调用父类的方法,实现当前方法的需求。

方便理解,我们可以把super替换成父类的名字。

那么在子类里面要初始化从父类继承过来的私有属性,需要调用父类的构造器,怎么用super来写呢?答案已经呼之欲出了对不对

super()是调用父类的无参构造器,super(参数1,参数...)是调用父类的有参构造器,super.方法名是调用父类的方法。特殊说明,调用父类的构造器我们一般选用super关键字且在第一行,而其他公开实例方法,this和super都可以:his是因为子类直接继承过来了,super也可以:在子类里面使用父类的方法完成当前对象的需求

同样的,这里的父类可以是间接父类。

class Student extends Person
{
    String stuID;
    public Student(String name,String stuID)
    {
       super(name);//调用父类的构造器一定是在子类的第一行
       this.stuID = stuID;
    
    }
}

对父类方法的重写:

class Student extends Person
{
    //...
    @Override
    public void doSelfIntroduction()
    {
        System.out.println("My name is " + getName() + " and my stuID is " + stuID);
    
    }//getName()前面默认省掉this,也可用super,结果是一样的
}

 

 在子类里面新增一个方法:
 

class Student extends Person
{
//...
    public void study()
    {
     System.out.println("I am studying!");
    }//新增方法
}

完整代码参考:
 

class Student extends Person
{
    String stuID;
    public Student(String name,String stuID)
    {
       super(name);
       this.stuID = stuID;
    
    }
    @Override
    public void doSelfIntroduction()
    {
        System.out.println("My name is " + getName() + " and my stuID is " + stuID);
    
    }
    public void study()
    {
     System.out.println("I am studying!");
    }
}

  • 37
    点赞
  • 47
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值