访问控制符

1 查看下列代码

 
  1. abstract class Vehicle {
  2.     public int speed() {
  3.         return 0;
  4.     }
  5. }
  6. class Car extends Vehicle {
  7.     public int speed() {
  8.         return 60;
  9.     }
  10. }
  11. class RaceCar extends Car {
  12.     public int speed() {
  13.         return 150;
  14.     }
  15. }
  16. public class TestCar {
  17.     public static void main(String[] args) {
  18.         RaceCar racer = new RaceCar();
  19.         Car car = new RaceCar();
  20.         Vehicle vehicle = new RaceCar();
  21.         System.out.println(racer.speed() + ", " + car.speed() + ", "
  22.      + vehicle.speed());
  23.     }
  24. }

上述代码运行的结果是

A. 0,0,0

B. 150,60,0

C. 150,150,150

D. 抛出运行时异常

参考答案

C 选项正确。

这是因为,子类可以重写(覆盖)继承自父类的方法,即方法名和参数列表与父类的方法相同,但方法的实现不同。当子类对象的重写方法被调用时(无论是通过子类的引用调用还是通过父类的引用调用),运行的是子类的重写后的版本。因此,本题的正确答案为选项 C。

2 编写正六边形类继承Shape,实现其area方法

在课上案例“根据周长计算不同形状图形的面积”基础上,编写正六边形类继承Shape,实现其area方法。

注:正六边形的面积计算公式为:0.0721 * c * c,其中c为周长。

参考答案:

实现此案例需要按照如下步骤进行。

步骤一:定义类Hexagon

定义名为Hexagon的类,表示正六边形,使该类继承自Shape类,代码如下所示:

 
  1. public class Hexagon extends Shape {
  2. }

步骤二:实现 area方法

在area方法中,根据正六边形的面积公式计算面积,代码如下所示:

  1. public class Hexagon extends Shape {
  2.     public Hexagon(double c) {
  3.         this.c = c;
  4.     }
  5.     /**
  6.      * 计算正六边形的面积
  7.      */
  8. public double area() {
  9. return 0.0721 * c * c;
  10. }
  11. }

步骤三:在测试类TestShape类中添加测试代码

在TestShape类中,构造Hexagon类型的对象,并将其放入数组中,代码如下所示:

 
  1. public class TestShape {
  2.     public static void main(String[] args) {
  3.         Shape[] shapes = new Shape[3];
  4.         shapes[0] = new Circle(4);//数组中的第一个元素为圆形对象
  5.         shapes[1] = new Square(4);//数组中的第二个元素为正方形对象
  6.         shapes[2] = new Hexagon(4);//数组中的第三个元素为正六边形对象
  7.         maxArea(shapes);
  8.     }
  9. public static void maxArea(Shape[] shapes) {
  10.         double max = shapes[0].area();
  11.         int maxIndex = 0;
  12.         for (int i = 1; i < shapes.length; i++) {
  13.             double area = shapes[i].area();
  14.             if (area > max) {
  15.                 max = area;
  16.                 maxIndex = i;
  17.             }
  18.         }
  19.         System.out.println("数组中索引为"+maxIndex+"的图形的面积最大,面积为:"+max);
  20.     }
  21. }

步骤四:运行

运行TestShape类,控制台输出结果如下所示:

 
  1. 数组中索引为0的图形的面积大,面积为:1.2736

观察上述输出结果,可以看出,shapes[0]表示的是圆形,周长相同的情况下,圆形的面积更大些。

本案例中,Hexagon类的完整代码如下所示:

  1. public class Hexagon extends Shape {
  2.     public Hexagon(double c) {
  3.         this.c = c;
  4.     }
  5.     /**
  6.      * 计算正六边形的面积
  7.      */
  8. public double area() {
  9. return 0.0721 * c * c;
  10. }
  11. }

TestShape类的完整代码如下所示:

 
  1. public class TestShape {
  2.     public static void main(String[] args) {
  3.         Shape[] shapes = new Shape[3];
  4.         shapes[0] = new Circle(4);//数组中的第一个元素为圆形对象
  5.         shapes[1] = new Square(4);//数组中的第二个元素为正方形对象
  6.         shapes[2] = new Hexagon(4);//数组中的第三个元素为正六边形对象
  7.         maxArea(shapes);
  8.     }
  9. public static void maxArea(Shape[] shapes) {
  10.         double max = shapes[0].area();
  11.         int maxIndex = 0;
  12.         for (int i = 1; i < shapes.length; i++) {
  13.             double area = shapes[i].area();
  14.             if (area > max) {
  15.                 max = area;
  16.                 maxIndex = i;
  17.             }
  18.         }
  19.         System.out.println("数组中索引为"+maxIndex+"的图形的面积最大,面积为:"+max);
  20.     }
  21. }

3 简述抽象类的意义

参考答案:

抽象类的意义在于:

1. 为其子类提供一个公共的父类型,避免该类被实例化;

2. 封装子类中的重复内容(成员变量和方法);

3. 定义公共抽象方法,由子类提供不同的实现。

4 编写建设银行接口CCB继承银联接口,并实现该接口

在课上案例“银行卡系统(实现银联接口)”的基础上,编写建设银行接口CCB。建设银行接口,用于描述中国建设银行发行的卡片功能,在满足银联接口的规则基础上,增加了支付燃气费的功能。

参考答案

实现此案例需要按照如下步骤进行。

步骤一: 定义建设银行接口

定义名为CCB的接口表示建设银行接口,用于描述中国建设银行发行的卡片功能,该接口需要满足银联接口的功能,因此,继承银联接口;该接口在具备银联接口的功能基础上,要求增加支付燃气费的功能,所以,在该接口中定义payGasBill方法,表示此功能,代码如下所示:

 
  1. /**
  2. * 接口:用于描述建设银行发行的卡片功能,在满足
  3. * 银联的规则基础上,添加自己特有的功能
  4. */
  5. public interface CCB extends UnionPay {
  6.     /**增加的支付燃气费功能*/
  7.     public void payGasBill(double number);
  8. }

步骤二:定义建设银行接口的实现类

首先,定义名为CCBImpl的类 ,该类实现CCB接口;另外,分析问题中的取钱功能,需要对余额信息进行存储,插入卡片以后需要输入密码后才能进行取钱,因此,在CCBImpl类中定义double类型属性money表示账户余额以及String类型属性pwd表示卡片的密码,代码如下所示:

 
  1. /**
  2. * 类:用于描述建设银行实际发行的卡片
  3. * 该卡片具有的功能来自于继承的已经符合银联规范的CCB接口
  4. */
  5. public class CCBImpl implements CCB {
  6.     private double money;
  7.     private String pwd;
  8.     
  9.     public CCBImpl(double money,String pwd){
  10.         this.money = money;
  11.         this.pwd = pwd;
  12.     }
  13. }

步骤三:实现检查密码、获取余额、取款、支付燃气费功能

在CCBImpl类实现checkPwd方法、getBalance方法、drawMoney方法以及payGasBill方法,代码如下所示:

 
  1. /**
  2. * 类:用于描述建设银行实际发行的卡片
  3. * 该卡片具有的功能来自于继承的已经符合银联规范的CCB接口
  4. */
  5. public class CCBImpl implements CCB {
  6.     private double money;
  7.     private String pwd;
  8.     
  9.     public CCBImpl(double money,String pwd){
  10.         this.money = money;
  11.         this.pwd = pwd;
  12.     }
  13.     
  14.     @Override
  15.     public double getBalance() {        
  16.         return money;
  17.     }
  18.     @Override
  19.     public boolean drawMoney(double number) {
  20.         if(number <= money){
  21.             money -=number;
  22.             return true;
  23.         }
  24.         return false;
  25.     }
  26.     @Override
  27.     public void payGasBill(double number) {
  28.         if(number < money){
  29.             money-=number;
  30.         }
  31.     }
  32.     @Override
  33.     public boolean checkPwd(String input) {
  34.         if(pwd.equals(input))
  35.             return true;
  36.         else
  37.             return false;
  38.     }
  39. }

以上四个方法的实现逻辑为:

取钱功能的实现为在当前余额的基础上减去要取的金额,如drawMoney方法的实现。

支付燃气费功能的实现为当前余额的基础上减去要支付的金额,如payGasBill方法的实现。

检查密码功能的实现为检查卡的密码与用户输入的密码是否相等,如果相等返回true,否则返回false,如checkPwd方法的实现。

获取余额功能的实现为类CCBImpl中的money属性即表示余额,将其返回即可,如getBalance方法的实现。

步骤四:测试

在TestUnionPay类中,测试银联接口提供的方法,是否成功实现,代码如下所示:

 
  1. import java.util.Scanner;
  2. /**
  3. * 测试实现接口后的类的方法调用
  4. */
  5. public class TestUnionPay {
  6.     public static void main(String[] args) {
  7.         //ICBCImpl icbc = new ICBCImpl(2000,"123456");
  8.         //ICBC icbc = new ICBCImpl(2000,"123456");
  9.         //UnionPay icbc = new ICBCImpl(2000,"123456");
  10.         //UnionPay icbc = new ABCImpl(2000,"123456");
  11.         UnionPay ccb = new CCBImpl(2000,"123456");
  12.         Scanner input = new Scanner(System.in);
  13.         System.out.println("请输入密码:");
  14.         if(ccb.checkPwd(input.next())){
  15.             System.out.println("请输入金额:");
  16.             double num = Double.parseDouble(input.next());
  17.             if(ccb.drawMoney(num)){
  18.                 System.out.println("取钱成功,卡余额为:"+icbc.getBalance());
  19.             }
  20.             else{
  21.                 System.out.println("取钱失败");
  22.             }
  23.         }else{
  24.             System.out.println("密码错误");
  25.         }
  26.     }
  27. }

查看上述代码,可以看出上述代码是采用CCBImpl类来实例化银联接口UnionPay的,运行后,实现了取款功能。

本案例中,UnionPay接口的完整代码如下所示:

 
  1. /**
  2. * 接口:用于描述银联统一制定的规则
  3. */
  4. public interface UnionPay {
  5.     /**查看余额*/
  6.     public double getBalance();    
  7.     /**取钱*/
  8.     public boolean drawMoney(double number);
  9.     /**检查密码*/
  10.     public boolean checkPwd(String input);
  11. }
 

CCB接口的完整代码如下所示:

 
  1. /**
  2. * 接口:用于描述建设银行发行的卡片功能,在满足
  3. * 银联的规则基础上,添加自己特有的功能
  4. */
  5. public interface CCB extends UnionPay {
  6.     /**增加的支付燃气费功能*/
  7.     public void payGasBill(double number);
  8. }
 

CCBImpl类的完整代码如下所示:

 
  1. /**
  2. * 类:用于描述建设银行实际发行的卡片
  3. * 该卡片具有的功能来自于继承的已经符合银联规范的CCB接口
  4. */
  5. public class CCBImpl implements CCB {
  6.     private double money;
  7.     private String pwd;
  8.     
  9.     public CCBImpl(double money,String pwd){
  10.         this.money = money;
  11.         this.pwd = pwd;
  12.     }
  13.     
  14.     @Override
  15.     public double getBalance() {        
  16.         return money;
  17.     }
  18.     @Override
  19.     public boolean drawMoney(double number) {
  20.         if(number <= money){
  21.             money -=number;
  22.             return true;
  23.         }
  24.         return false;
  25.     }
  26.     @Override
  27.     public void payGasBill(double number) {
  28.         if(number < money){
  29.             money-=number;
  30.         }
  31.     }
  32.     @Override
  33.     public boolean checkPwd(String input) {
  34.         if(pwd.equals(input))
  35.             return true;
  36.         else
  37.             return false;
  38.     }
  39. }

TestUnionPay类的完整代码如下所示:

 
  1. import java.util.Scanner;
  2. /**
  3. * 测试实现接口后的类的方法调用
  4. */
  5. public class TestUnionPay {
  6.     public static void main(String[] args) {
  7.         //ICBCImpl icbc = new ICBCImpl(2000,"123456");
  8.         //ICBC icbc = new ICBCImpl(2000,"123456");
  9.         //UnionPay icbc = new ICBCImpl(2000,"123456");
  10.         //UnionPay icbc = new ABCImpl(2000,"123456");
  11.         UnionPay ccb = new CCBImpl(2000,"123456");
  12.         Scanner input = new Scanner(System.in);
  13.         System.out.println("请输入密码:");
  14.         if(ccb.checkPwd(input.next())){
  15.             System.out.println("请输入金额:");
  16.             double num = Double.parseDouble(input.next());
  17.             if(ccb.drawMoney(num)){
  18.                 System.out.println("取钱成功,卡余额为:"+icbc.getBalance());
  19.             }
  20.             else{
  21.                 System.out.println("取钱失败");
  22.             }
  23.         }else{
  24.             System.out.println("密码错误");
  25.         }
  26.     }
  27. }
 

5 关于接口和抽象类,下列说法正确的是

A. 抽象类和接口都不能实例化。

B. 接口里只能包含抽象方法,抽象类则可以包含普通方法。

C. 接口里不包含构造器,抽象类里可以包含构造器。

D. 一个类只能实现一个接口

参考答案:

选项ABC是正确的。

选项A,抽象类和接口都不能实例化对象,用于被其他类继承和实现。

选项B,接口里只能包含抽象方法,抽象类则可以包含普通方法和抽象方法。

选项C,接口里不包含构造器;抽象类里可以包含构造器,抽象类里的构造器并不是用于创建对象,而是让其子类调用这些构造器来完成属于抽象类的初始化操作。

选项D,一个类只能有一个直接父类;但一个类可以直接实现多个接口,实现多继承。

posted @ 2018-01-22 16:49  清风已来  阅读(316)  评论(0编辑  收藏  举报