引言
你在学习JAVA之前我学过一点C++所以在学习JAVA的继承和多态前还是觉得自己应该会很轻松拿捏住JAVA的继承和多态的。然而事实并非如此…
父类和子类
父类和子类便是继承的直接表现
我们用类来表示一类拥有共同点的一类对象,但不同对象间又有各自不同的特点。例如几何图形,几何图形作为一个大的类,而几何图形又可以分成圆形,矩形,多边形等等。我们就可以把几何图形看成父类,其下面的矩形,圆形看作子类。子类继承了父类的属性,子类又拥有更具体的属性。
extends为继承的关键字
父类也叫超类和基类
子类也叫继承类和派生类
关于父类子类需要注意的点 |
---|
1 .子类并不是父类的子集,通常情况下子类会比父类包含更多的信息和方法 |
2. 父类中的私有数据域在类外是不可以访问的,因此在子类中不能使用,但可以通过继承父类公共的修改器修改私有数据域 |
3. 在JAVA中一个类只可能继承一个父类。这种限制称为单一继承 |
下面我们看一个例子
我们定义一个GeometricObject类
public class GeometricObject {
private String color ="white";
private boolean filled;
private java.util.Date dateCreated;
public GeometricObject() {
dateCreated = new java.util.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 java.util.Date getDateCreated(){
return dateCreated;
}
public String toString() {
return "created on " + dateCreated + "\ncolor: " + color + " and filled: " + filled;
}
}
接下来我们定义的Circle类,Circle继承了GeometricObject,Circle既包含了GeometricObject中所有的方法,Circle中又添加了自己的方法
public class Circle extends GeometricObject{
private double radius;
public Circle() {
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 getPerimerter() {
return 2 * radius * Math.PI;
}
public void printCircle() {
System.out.println("The circle is created " + getDateCreated() + " and the radius is " + radius);
}
}
使用super关键字
super代指父类,可以用于调用父类中的普通方法和构造方法
调用父类的构造方法:
super()或者super(arguments):
super()调用父类无参的构造方法
super(arguments)调用相对应参数的父类构造方法
语句super()或者super(arguments)必须出现在子类构造方法的第一行,这是显式调用父类构造方法的唯一方式。
构造方法可以调用重载的构造方法或者父类的构造方法。如果他们都没有被显式的调用,编译器就会自动地将super()作为构造方法的第一条语句。
例如
构造方法链
在我们创建一个类的实例时,如果这个类是由多个父类子类继承下来的,我们在创建这个实例时构造方法的顺序会是怎样呢?
举一个例子
上面这段代码的输出为:
为什么是这样呢?
因为在JAVA中,在任何情况下,构造一个类的实例时,将会调用沿着继承链的所有父类的构造方法。当构造一个子类的对象时,子类的构造方法会在完成自己的任务之前,首先会调用它的父类的构造方法。这个过程持续到沿着这个继承层次结构的最后一个构造方法被调用为止。
这就是构造方法链
给出上段代码的顺序示意图:
方法重写
在重写一个方法时,子类必须使用和父类一样的签名来对该方法重新定义(函数的签名:就是指函数的返回类型、函数名、参数个数、参数类型的总和)
关于方法重写有以下几点需要特别注意:
关于方法重写需要注意的点 |
---|
1. 重写方法和被重写的方法必须拥有完全相同的签名,以及一样或者兼容的返回类型 ,兼容的含义是重写方法的返回类型可以是被重写方法返回类型的子类型 |
2.仅实例方法可访问时,才能被重写。因为私有方法在类外是不能被访问的,所有不能被重写,如果子类中定义的方法在父类中是私有的,那么这两个方法完全没有关系。 |
3.静态方法可以被继承但不能被重写。如果父类中的静态方法在子类中被重新定义,那么 父类中定义的静态方法会被隐藏。可以使用语法“父类名.静态方法名(SuperClassName。staticMethodName) 调用隐藏的静态方法。 |
方法重写和重载的异同
重载意味着使用相同的方法名,但是用不一样的签名来定义方法,重写便是使用相同的签名在子类中提供一个新的方法实现方式
举个🌰
重写和重载需要注意的点 |
---|
1.方法重写只能发生在具有继承关系的子类中,重载既可以在自己类中重载也可以在具有继承关系的子类中重载 |
2.方法重写具有相同的签名;方法重载具有相同的方法名,但不同的参数列表。 |
为了避免错误,可以使用一种特殊的Java语法,称为重写标注(override annotation)
多态
多态就意味着父类的变量可以引用子类型的对象,我的理解就是子类型涵盖了父类的所有特征,因此父类的变量引用子类的对象时,父类的变量可以将子类对象中和父类一致的方法属性引用过来并且也不会因为子类特有的父类中没有的方法属性而发生错误。在我看来,这是Java具有较好兼容性的一个表现。
public class PolymorphismDemo {
public static void main(String[] args) {
// TODO 自动生成的方法存根
displayObject(new Circle(1,"red",false));
displayObject(new Rectangle(1,1,"black",true));
}
public static void displayObject(GeometricObject object) {
System.out.println("Created on " + object.getDateCreated() + ". Color is " + object.getColor());
}
}
输出为:
动态绑定
动态绑定的含义就是方法可以继承链中的多个类实现。JVM决定运行时调用哪个方法。
下面举个🌰
public class DynamicBindDemo {
public static void main(String[] args) {
m(new GraduateStudent());
m(new Student());
m(new Person());
m(new Object());
}
public static void m(Object x) {
System.out.println(x.toString());
}
}
class GraduateStudent extends Student{
}
class Student extends Person{
@Override
public String toString() {
return "Student";
}
}
class Person extends Object{
@Override
public String toString() {
return "Person";
}
}
输出为:
通过这个结构体应该可以更好的理解动态绑定的含义
下期再会~~~~~~~~~~~~