继承就是从已经存在的类中定义新的类,拥有父类签名的同时也能定义自己的签名,甚至改写父类签名中的内容(即重写)
可以类比你自己继承了父亲的某些特征,但同时也有自己的特征。
继承的目的是避免冗余、使系统易于理解和维护。这里的冗余来自设计的许多具有相同特征的类,比如对圆、矩形和三角形建模,它们可能都有颜色和填充与否的特征,如果一个一个地添加颜色和填充的特征就会显得繁复。
父类别称:超类、基类
子类别称:继承类、派生类
关键字:extends
下面是一个图形类(父类)、圆类和矩形类(子类)的例子
首先,图形类GeometricObject
包含了圆形和矩形都具有的特征 – 颜色、是否填充和对象创建的时间
然后是一些可供访问的方法:
①两个构造函数,一个无参,一个有参可以初始化对象属性
②颜色和是否填充的getters&setters
③时间的获取方式
④返回这个对象的字符串表述的方法(表述的是对象属性)
public class GeometricObject {
private String color = "white";
private boolean filled;
private Date dateCreated;
/** 创建一个无参构造函数 */
public GeometricObject() {
dateCreated = new Date(); // 记录创建此对象的时间
}
/** 创建一个有指定特征的构造函数 */
public GeometricObject(String color, boolean filled) {
dateCreated = new Date();
this.color = color;
this.filled = filled;
}
/** 返回颜色 */
public String getColor() {
return color;
}
/** 重设颜色 */
public void setColor(String color) {
this.color = color;
}
/** 返回此对象是否填充 */
public boolean isFilled() {
return filled;
}
/** 重新设置填充属性 */
public void setFilled(boolean filled) {
this.filled = filled;
}
/** 返回对象创建时间 */
public Date getDateCreated() {
return dateCreated;
}
/** 返回这个对象的字符串表示 */
public String toString() {
return "created on " + dateCreated + "\ncolor: " + color +
" and filled: " + filled;
}
}
子类之圆形Circle
继承了GeometricObject
中所有可访问的数据域和方法,父类的私有数据域(private)是无法访问的,除非父类中有该数据的修改器(setters)。
添加了属于自己的数据radius
,当然还有配套的getter&setter,由此可见子类并不是父类的子集,子类中的内容往往比父类更丰富。
另外还添加了直接打印对象圆信息的类printCircle
,分别返回直径、周长和面积的类:getDiameter
、getPerimeter
、getArea
public class Circle extends GeometricObject {
private double radius;
public Circle() {
}
public Circle(double radius) {
this.radius = radius;
}
public Circle(double radius, String color, boolean filled) {
this.radius = radius;
setColor(color);
setFilled(filled);
}
/** 返回圆半径 */
public double getRadius() {
return radius;
}
/** 设置半径 */
public void setRadius(double radius) {
this.radius = radius;
}
/** 返回面积 */
public double getArea() {
return radius * radius * Math.PI;
}
/** 返回直径 */
public double getDiameter() {
return 2 * radius;
}
/** 返回周长 */
public double getPerimeter() {
return 2 * radius * Math.PI;
}
/** 打印此圆的信息 */
public void printCircle() {
System.out.println("The circle is created " + getDateCreated() +
" and the radius is " + radius);
}
}
子类之矩形Rectangle
与Circle
类似,继承了父类并且添加了自己的数据width
和height
,顺便一提,在计算机科学中一般用宽度(width)表示水平长度、高度(height)表示垂直长度,而不是数学中的长、宽
有了width
和height
,自然就有配套设施getters&setters和返回面积、周长的方法getArea
、getPerimeter
public class Rectangle extends GeometricObject {
private double width;
private double height;
public Rectangle() {
}
public Rectangle(double width, double height) {
this.height = height;
this.width = width;
}
public Rectangle(double width, double height, String color, boolean filled) {
this.height = height;
this.width = width;
setColor(color);
setFilled(filled);
}
/** 返回宽度 */
public double getWidth() {
return width;
}
/** 设置宽度 */
public void setWidth(double width) {
this.width = width;
}
/** 返回高度 */
public double getHeight() {
return height;
}
/** 设置高度 */
public void setHeight(double height) {
this.height = height;
}
/** 返回面积 */
public double getArea() {
return width * height;
}
/** 返回周长 */
public double getPerimeter() {
return 2 * (width + height);
}
}
最后编写一个测试类,创建一个圆和一个矩形,调用类中的方法
public class TestCircleRectangle {
public static void main(String[] args) {
Circle circle = new Circle(1);
System.out.println("A circle " + circle.toString());
System.out.println("The color is " + circle.getColor());
System.out.println("The radius is " + circle.getRadius());
System.out.println("The area is " + circle.getArea());
System.out.println("The diameter is " + circle.getDiameter());
Rectangle rectangle = new Rectangle(2, 4);
System.out.println("\nA rectangle " + rectangle.toString());
System.out.println("The area is " + rectangle.getArea());
System.out.println("The perimeter is " + rectangle.getPerimeter());
}
}
结果显示:
A circle created on Mon Jul 20 16:55:04 CST 2020
color: white and filled: false
The color is white
The radius is 1.0
The area is 3.141592653589793
The diameter is 2.0
A rectangle created on Mon Jul 20 16:55:04 CST 2020
color: white and filled: false
The area is 8.0
The perimeter is 12.0
1.子类并不是父类的子集,子类的内容一般比父类要多。
2.父类中的私有数据不能被其他类访问 / 修改,所以只能通过在父类中该数据的访问器 / 修改器(如果有的话),才能访问 / 修改。
3.子类和父类一定存在 “是一种” 关系。比如圆形(矩形)是一种图形,具有颜色和是否填充的特征。
但不是所有 “是一种” 关系都能构成子、父类关系。例如,虽然正方形是一种矩形,可它不能直接继承与矩形,因为它不具备矩形的width
和height
特征;正方形只需要一个边长的特征数据,所以最好让正方形类直接继承于图形类,然后声明一个私有变量side
。
4.不能本末倒置,千万别“为了继承而继承”。即使人(Person)和狮子(Lion)都具有height
和weight
的特征,但是这两者之间的继承是没有意义的,父类和子类必须保持有 “是一种” 关系。
5.Java有单一继承的限制,也就是说通过extends
关键字来定义的子类绝对只能有一个父类。要注意的是Java中通过接口还是可以间接实现多重继承的,只是不像其他一些程序语言可以直接多重继承而已。