继承

面向对象编程中,代码复用方面,除了使用类进行基本的封装,还可以通过继承,对已有的类进行修改、扩展等操作。

超类与子类

超类与子类是相对的关系,下面的代码,我们在HelloProject中添加一个CSuv类。

Java
public class CSuv extends CAuto {
	public CSuv() throws Exception {
		super("X-20",5);
	}
}

先看几个新的要素:

  • extends关键字,用于指定类继承于哪个类,从字面意思上看,继承的主要功能就是扩展。这里,CSuv类是从CAuto类继承而来,那么CSuv就是CAuto的子类,相应的,CAuto就是CSuv的超类(也称为基类或父类)。
  • super关键字表示父类。本例,在CSuv类的构造方法中使用super关键字引用了CAuto中的CAuto(String,int)构造方法,其中,model默认设置为X-20,而车门数量默认设置为5。

下面的代码,我们在main()方法中测试CSuv类的使用。

Java
public class Hello {
	public static void main(String[] args) throws Exception{
		CSuv suv = new CSuv();
		System.out.println(suv.model);
		System.out.println(suv.getDoorCount());
		suv.drive();
	}
}

代码执行结果如下图。

我们可以看到,通过继承,在子类中可以访问超类中的非私有成员,如model属性、getDoorCount()方法、drive()方法。

关于类的继承,还需要注意一个问题,即类是否可以被继承;默认情况下,一个类是允许被继承的,但如果一个类不允许被继承,就需要在定义类时使用final关键字。如下面的代码。

Java
public final class CSuv extends CAuto {
	public CSuv() throws Exception {
		super("X-20",5);
	}
}

当一个类使用了final关键字定义时,就不能被继承了;下面的代码,我们在默认包中创建一个CTest类,让其继承CSuv类。

Java
public class CTest extends CSuv {
}

在开发环境中会给出提示,并给出修改建议,如下图。

重写与扩展

下面的代码,我们在CSuv中扩展和重写一些成员。

Java
public final class CSuv extends CAuto {
	public CSuv() throws Exception {
		super("X-20",5);
	}
	// 扩展成员
	public boolean isAwd;
	// 重写成员
	public void drive() {
		super.drive();
		if(isAwd)
			System.out.printf("%s 四驱行驶中...", model);
		else
			System.out.printf("%s 两驱行驶中...", model);
	}
}

本例,我们添加了一个属性isAwd,表示SUV是否为全轮驱动(All-wheel drive),定义为boolean类型。这里,还重写了drive()方法,分别显示四驱和两驱不同状态下的行驶信息,其中,还使用了super引用了超类,即CAuto类中的drive()方法。

下面的代码,在main()方法中使用CSuv类中的isAwd和drive()方法。

Java
public class Hello {
	public static void main(String[] args) throws Exception{
		CSuv suv = new CSuv();
		suv.isAwd = true;
		suv.drive();
		System.out.println();
		suv.isAwd = false;
		suv.drive();
	}
}

代码执行结果如下图。

抽象类与抽象方法

抽象类可以看作是一个类实现的模板或半成品,如下面的代码,我们在默认包中创建一个CUnitBase类。

Java
public abstract class CUnitBase {
	// 构造函数
	public CUnitBase(String sModel) {
		model = sModel;
	}
	// 属性
	public String model;
	// 抽象方法
	public abstract void moveTo(int x, int y);
}

代码中,我们定义CUnitBase类时使用了abstract关键字,这样就不能使用new关键字创建它的实例。在CUnitBase类中的成员包括一个构造方法,一个model属性,一个抽象方法moveTo()。

接下来,我们使用CPlane类继承CUnitBase类,如下面的代码。

Java
public class CPlane extends CUnitBase {
	// 构造方法
	public CPlane(String sModel) {
		super(sModel);
	}
	// 重写
	public void moveTo(int x, int y) {
		System.out.printf("%s 飞行到(%d, %d)",model,x,y);
	}
}

CPlane类中,我们重写了构造方法和moveTo(int, int)方法;下面的代码,在main()方法中测试CPlane类的使用。

Java
public class Hello {
	public static void main(String[] args){
		CPlane j20 = new CPlane("歼20");
		j20.moveTo(35, 115);
	}
}

代码执行结果如下图。

Object类

Object类定义在java.lang包,是Java中唯一一个没有超类的类,它也是所有Java中其它类的终极超类。

当我们定义自己类时,如果没有指定继承的类,如CAuto类;那么,这个类默认就继承于Object类,这也是为什么在没有定义任何成员的情况下,对象就可以使用很多方法,如toString()、getClass()等。

下面的代码,我们通过CAuto类的实例来看看Object类中的定义一些非私有成员的使用。

Java
public class Hello {
	public static void main(String[] args) throws Exception{
		CAuto car = new CAuto();
		System.out.println(car.toString());
		System.out.println(car.getClass().getName());
	}
}

其中,car.toString()方法会返回对象在系统内部的标识。而car.getClass()会返回car对象的类型(Class类),getName()方法则返回类型的名称。代码执行结果如下图。

如果需要对象的toString()方法返回更有意义的内容,可以在CAuto类中重写toString()方法,如下面的代码。

Java
public class CAuto {
	// 重写toString()方法
	public String toString() {
		return getClass().getName() + " Object " + model;
	}
   // 其它代码
}

修改main()方法的代码如下。

Java
public class Hello {
	public static void main(String[] args) throws Exception{
		CSuv suv = new CSuv();
		System.out.println(suv.toString());
	}
}

运行结果如下图。

我们可以看到,CSuv作为CAuto类的子类,也继承了重写的toString()方法。

再来看Object类中equals()方法的应用,如下面的代码,我们以两个CAuto对象为例。

Java
public class Hello {
	public static void main(String[] args) throws Exception{
		CAuto car1 = new CAuto();
		CAuto car2 = new CAuto();
		System.out.println(car1.equals(car2));
	}
}

代码执行如下图,其中显示false,表示car1和car2并不相等。

实际上,car1和car2对象中model和doorCount数据是相等的,但它们属于不同的实例;Object类中的equals()方法在比较两个对象时,会判断两个对象是否为同一实例,如下面的代码就会显示true。

Java
public class Hello {
	public static void main(String[] args) throws Exception{
		CAuto car1 = new CAuto();
		CAuto car2 = car1;
		System.out.println(car1.equals(car2));
	}
}

有些类型为了更有效的表达相等的含义,会重写equals()方法,如Integer类;下面的代码用于比较整数对象是否相等。

Java
public class Hello {
	public static void main(String[] args){
		Integer x = Integer.valueOf(10);
		Integer y = Integer.valueOf(10);
		Integer z = Integer.valueOf(99);
		System.out.println(x.equals(y));
		System.out.println(x.equals(z));
	}
}

代码显示结果如下图。

本站内容均为原创作品,转载请注明出处,本页面网址为:http://caohuayu.com/chy/article/Article.aspx?code=cc001008