任务描述
我们都知道,生活中的继承无处不在,在数学王国的领域也是如此。最近数学王国中一位名叫Shape的父亲有一个烦心事,他有两个儿子Circle和Rectangle,这两个儿子比较叛逆,虽然Sharp苦口婆心的教育他们说要继承自己的方法,但他们觉得没有父亲也能计算自己的面积。无奈之下Shape找到了你,请你来编写程序告诉他的两个儿子要继承他的方法。
相关知识
继承的概念
继承是java面向对象编程技术的一块基石,因为它允许创建分等级层次的类。
兔子和羊属于食草动物类,狮子和豹属于食肉动物类。
食草动物和食肉动物又都属于动物类。
如果在程序设计中不使用继承,则可能造成代码存在重复,导致代码量大且臃肿,以至于维护性不高,因为后期需要修改重复代码段时,就需要修改大量代码,容易出错。
所以要从根本上解决这个问题,就需要继承,将多段代码中相同的部分提取出来组成一个父类。
类的继承格式
在 Java 中通过 extends 关键字可以申明一个类是从另外一个类继承而来的,一般形式如下:
class 父类 {
...
}
class 子类 extends 父类 {
...
}
继承的特性
子类拥有父类非private的属性和方法。
子类可以拥有自己的属性和方法,即子类可以对父类进行扩展。
子类可以用自己的方式实现父类的方法,即重写父类的方法。
Java的继承是单继承,但是可以多重继承。单继承就是一个子类只能继承一个父类;多重继承就是,例如A类继承B类,B类继承C类,所以按照关系就是C类是B类的父类,B类是A类的父类,这是Java继承区别于C++继承的一个特性。
访问控制的继承
请注意以下方法继承的规则:
父类中声明为 public 的方法在子类中也必须为 public。
父类中声明为 protected 的方法在子类中要么声明为 protected,要么声明为 public,不能声明为 private。
父类中声明为 private 的方法,不能够被继承。
final关键字
final 关键字声明类可以把类定义为不能被继承,即“最终”的类;如果用于修饰方法,则该方法不能被子类重写。
注:实例变量也可以被定义为 final 类型,被定义为 final 类型的变量不能被修改。被声明为 final 的类的方法会被自动声明为 final 类型,但是其实例变量并不是 final 类型。
抽象类
在面向对象的概念中,所有的对象都是通过类来描绘的,但是反过来,并不是所有的类都是用来描绘对象的,如果一个类中没有包含足够的信息来描绘一个具体的对象,这样的类就是抽象类。
在Java语言中使用 abstract 关键字来定义抽象类。切记,抽象类不能实例化对象,只能先定义一个非抽象子类继承该抽象类,再通过这个子类实例化对象。
public abstract class ClassName {
...
}
抽象方法
如果你想设计这样一个类,该类包含一个特别的成员方法,该方法的具体实现由它的子类确定,那么你可以在父类中声明该方法为抽象方法。
abstract 关键字同样可以用来声明抽象方法,抽象方法只包含一个方法名,而没有方法体。抽象方法没有定义,方法名后面直接跟一个分号,而不是花括号。
public abstract class ClassName {
public abstract returnType methodName();
}
声明抽象方法会造成以下两个结果:
如果一个类包含抽象方法,那么该类必须是抽象类。
任何子类必须重写父类的抽象方法,或者声明自身为抽象类。
继承抽象方法的子类必须重写该方法。否则,该子类也必须声明为抽象类。最终,必须有子类实现该抽象方法,否则,从最初的父类到最终的子类都不能用来实例化对象。
编程要求
本关的编程任务是补全右侧代码片段中Begin至End中间的代码,具体要求如下:
将Shape类定义为抽象类,Shape类的getAcreage()方法(获取面积)定义为抽象方法。
将Circle类和Rectangle类定义为Shape类的子类,分别重写Shape类的抽象方法getAcreage(),返回各自的面积。
PI取3.1415926.
特别注意:由于类型精度的问题,计算圆的面积的时候,请使用 PI * r * r
评测说明
平台将自动编译补全后的代码,并生成若干组测试数据,接着根据程序的输出判断程序是否正确。
以下是测试样例:
测试输入:
2
2 3
预期输出:
12.5663704
6.0
package step1;
import java.util.Scanner;
public class ShapeTrouble {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
double radius = scanner.nextDouble();
double length = scanner.nextDouble();
double width = scanner.nextDouble();
Circle circle = new Circle(radius);
Rectangle rectangle = new Rectangle(length, width);
System.out.println(circle.getAcreage());
System.out.print(rectangle.getAcreage());
}
}
abstract class Shape {
abstract double getAcreage();
}
class Circle extends Shape {
double radius;
double pi=3.1415926;
public Circle(double radius){
this.radius=radius;
}
@Override
public double getAcreage() {
return pi*radius*radius;
}
}
class Rectangle extends Shape {
double length;
double width;
public Rectangle(double length,double width){
this.length=length;
this.width=width;
}
@Override
public double getAcreage() {
return length*width;
}
}
任务描述
小明工作的公司最近要升级系统了,原先的员工管理系统有一个Employee类用于管理员工的姓名、出生年月、职位等个人信息,现在老板希望新增加一个Salary类用于管理员工的工资。小明公司的老板非常抠门,他要求Salary类要继承Employee类,以减小后期对系统的维护成本。小明感觉无从下手,便请你来帮忙。
相关知识
super关键字
对于继承父类的子类而言,有时我们需要在子类中访问父类的方法,此时便可以使用 super 关键字,请看下面这个示例:
class People {
People(String name, int age) { //父类构造方法
this.name = name;
this.age = age;
}
private String name;
private int age;
}
class Student extends People {
Student(String name, int age, String studentNumber) { //子类构造方法
super(name, age); //调用父类构造方法
this.studentNumber = studentNumber; //继续完成子类自身的构造方法
}
private String studentNumber;
}
在上面这个例子中,父类People有自身的构造方法,当子类Student继承People类时,显然我们不希望将父类的构造方法在子类中再实现一遍,否则就是代码冗余,此时便在子类的构造方法中先使用super()来调用父类构造方法,然后再根据实际需求完成子类自身的构造方法。
如果是访问父类的成员方法,则格式为:
super.methodName();
super关键字与this关键字的总结:
super:通过super关键字来实现对父类成员的访问,用来引用当前的类的父类。
this:指向当前的类的引用。
同学们要灵活运用这两个关键字,以实现不同的需求。
编程要求
本关的编程任务是补全右侧代码片段中Begin至End中间的代码,具体要求如下:
使用构造方法初始化类。
在Salary类使用super关键字调用父类的方法。
定义introduction方法介绍员工信息,格式见测试样例。
评测说明
平台将自动编译补全后的代码,并生成若干组测试数据,接着根据程序的输出判断程序是否正确。
以下是测试样例:
测试输入:
张三 1995.07 程序员 4500
预期输出:
员工姓名:张三 出生年月:1995.07 职位:程序员 薪水:4500.0
注:各项之间用空格隔开,冒号使用中文字符。
package step2;
import java.util.Scanner;
public class SystemUpdate {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String name = scanner.next();
String birth = scanner.next();
String position = scanner.next();
double salary = scanner.nextDouble();
Salary employee = new Salary(name, birth, position, salary);
employee.introduction();
}
}
/********** Begin *********/
class Employee {
String name;
String birth;
String position;
public Employee(String name,String birth,String position) {
this.name=name;
this.birth=birth;
this.position=position;
}
}
class Salary extends Employee {
private double salary;
Salary(String name,String birth,String position,double salary){
super(name,birth,position);
this.salary=salary;
}
public void introduction() {
System.out.println("员工姓名:"+name+" "+"出生年月:"+birth+" "+"职位:"+position+" "+ "薪水:"+salary);
}
}
/********** End *********/
任务描述
小明新学习了多态的概念,老师布置作业要编写一个小程序,用多态的概念实现对猫和狗的介绍。可惜小明学艺不精,只好请你来帮忙。
相关知识
多态
多态就是同一个方法,使用不同的实例而执行不同操作,如图所示:
同样是打印这一个方法,如果对象是彩色打印机,则打印出来的是彩色文件;如果对象是黑白打印机,则打印出来的是黑白文件。多态是对象多种表现形式的体现。
多态的优点:
消除类型之间的耦合关系
可替换性
可扩充性
接口性
灵活性
简化性
多态存在的三个必要条件:
继承
重写
父类引用指向子类对象
例如:
class Parent {
public void introduction() {
...
}
}
class Child extends Parent {
public void introduction() {
...
}
}
public class Main {
public static void main(String[] args) {
Parent person = new Child(); //父类引用指向子类对象
person.introduction(); //执行的是Child类的introduction方法
}
}
当使用多态方式调用方法时,首先检查父类中是否有该方法,如果没有,则编译错误;如果有,再去调用子类的同名方法。
编程要求
本关的编程任务是补全右侧代码片段中Begin至End中间的代码,具体要求如下:
使用多态的方式调用对象成员方法。
依次输出猫吃的东西、猫做的事情、狗吃的东西、狗做的事情,格式见测试样例。
评测说明
平台将自动编译补全后的代码,并生成若干组测试数据,接着根据程序的输出判断程序是否正确。
以下是测试样例:
测试输入:
预期输出:
吃鱼
抓老鼠
吃骨头
看家
Code:
package step3;
public class CatAndDog {
public static void main(String[] args) {
/********** Begin *********/
Animal cat=new Cat();
Animal dog=new Dog();
/********** End *********/
cat.eat();
cat.work();
dog.eat();
dog.work();
}
}
abstract class Animal {
abstract void eat();
abstract void work();
}
/********** Begin *********/
class Cat extends Animal {
public void eat() {
System.out.println("吃鱼");
}
public void work() {
System.out.println("抓老鼠");
}
}
class Dog extends Animal {
public void eat() {
System.out.println("吃骨头");
}
public void work() {
System.out.println("看家");
}
}
/********** End *********/