改写第3题的程序,利用组合来实现类复用。
由于已经建立了Person类和它的info方法,因此我再创建一个Teacher类时可以直接将Person组合进来,调用其info方法,源代码如下:
package pe;
/**
* 此为一个Teacher类,演示了通过组合获得Person类的info方法
* @author Liu XueZheng
* @version 1.0
*/
public class Teacher{
//创建一个Person实例
private Person p;
//定义构造器,形参为Person
public Teacher(Person p){
//将传入的实参赋给实例变量p
this.p = p;
}
//创建一个info方法,里面调用p的info方法
public void info(String name){
p.info(name);
}
public static void main(String[] args){
//此时需要显示创建被组合的对象
//Object p = new Person();
var p = new Person();
//新建一个Teacher对象
var t = new Teacher(p);
//调用t的info方法
t.info("xiaoTian");
}
}
这里将Teacher类也放入了pe包内,在调用Person类时便可省略路径名称。需要注意的一点是在main方法中创建实例时,如果是采用Object p = new Person(); 会引起编译错误。这牵扯到了多态的问题,等式左边声明了p是一个Object类的实例,但等式右边说明实际执行时p是一个Person类实例,在编译时是按照声明的类型来的,因此会造成后边将p作为实参传入var t = new Teacher(p)时报错,错误如下:
原因就是Tracher构造器方法中的形参是一个Person类型,而传入的p在编译时是一个Object类型。
将Object改为var后便不存在这个问题,因为var会自动根据等式右边类型推测编译时类型。程序运行结果如下:
定义交通工具、汽车、火车、飞机这些类,注意它们的继承关
系,为这些类提供超过3个不同的构造器,并通过实例初始化块提取构
造器中的通用代码。
首先定义一个交通工具类作为父类,其具有使用寿命、单价、容纳人数三个成员变量。然后创建一个汽车类继承交通工具类。在交通工具类中利用实例初始化块对成员变量进行了初始化。源代码如下:
package vh;
//定义交通工具类
class Vehicle{
//定义使用寿命
protected int serviceLife;
//定义单价
protected double unitPrice;
//定义容纳人数
protected int capacity;
//定义启动方法
public void start(){
System.out.println("Start");
}
//定义实例初始化块为成员变量赋值
{
serviceLife = 20;
unitPrice = 10.0;
capacity = 12;
}
//定义无参构造器
public Vehicle(){
System.out.println("这是Vehicle类的一个无参构造器");
}
//定义一个参数的构造器
public Vehicle(String firstParam){
System.out.println("这是Vehicle类的一个参数的构造器,参数为:" + firstParam);
}
public Vehicle(String firstParam, String secondParam){
System.out.println("这是Vehicle类的两个参数的构造器,参数为:" + firstParam + ", " + secondParam);
}
}
//定义汽车类
class Car extends Vehicle{
//定义输出信息的info方法
public void info(){
System.out.println("Car的使用寿命为:" + serviceLife + "年");
System.out.println("Car的单价为:" + unitPrice + "万");
System.out.println("Car的容纳人数为:" + capacity + "人");
}
}
public class TestVehicle{
public static void main(String[] args){
//定义一个Vehicle实例,使用无参构造器
var v = new Vehicle();
//定义一个Vehicle实例,使用一个参数的构造器
var vOne = new Vehicle("one");
//定义一个Vehicle实例,使用两个参数的构造器
var vTwo = new Vehicle("one", "two");
//定义一个Car实例,使用默认构造器
var car = new Car();
//调用car的info方法
car.info();
}
}
输出结果如下:
这里由于Car类定义时没有定义构造器,因此其默认继承了父类的构造器,相当于系统自动为Car类创建了一个无参构造器,构造器中调用了父类的无参构造器,如下所示:
public Car(){
//调用父类的无参构造器
super();
}
如果想调用父类的其他构造器,需要传入对应参数。比如让Car类调用父类的一个参数的构造器,代码如下:
public Car(String oneParam){
//调用父类的一个参数的构造器
super(oneParam);
}
运行结果如下:
在Car中再新建一个三个参数的构造器,使其可以对三个成员变量赋值
public Car(int serviceLife, double unitPrice, int capacity){
this.serviceLife = serviceLife;
this.unitPrice = unitPrice;
this.capacity = capacity;
}
新建一个Car对象并利用三个参数的构造器进行初始化,打印其成员变量值
var carTwo = new Car(15, 10, 6);
carTwo.info();
结果如下:
由于新构造器没有显示调用父类构造器,因此其隐式地调用了父类的无参构造器,然后才执行子类的新构造器。