Java继承


继承是一个类获取另一类的成员(属性和方法)的过程,它是代码复用的一种手段。

继承其他类的类称为子类(派生类),被继承的类称为父类(基类)。

extends关键字


extends是用于继承类的关键字,以下是extends关键字的语法:

class Super {
    .....
    .....
}
class Sub extends Super {
    .....
    .....
}

例子


以下是Java继承的示例,在此示例中,可以看到有两个类Calculation和My_Calculation。

My_Calculation使用extends关键字继承了Calculation类的方法addition()和Subtraction()。

class Calculation {
    int z;
	
    public void addition(int x, int y) {
        z = x + y;
        System.out.println("The sum of the given numbers:"+z);
    }
	
    public void Subtraction(int x, int y) {
        z = x - y;
        System.out.println("The difference between the given numbers:"+z);
    }
}

public class My_Calculation extends Calculation {
    public void multiplication(int x, int y) {
        z = x * y;
        System.out.println("The product of the given numbers:"+z);
    }
	
    public static void main(String args[]) {
        int a = 20, b = 10;
        My_Calculation demo = new My_Calculation();
        demo.addition(a, b);
        demo.Subtraction(a, b);
        demo.multiplication(a, b);
    }
}

编译并执行上述代码,如下所示:

javac My_Calculation.java
java My_Calculation

执行该程序后,将产生以下结果:

The sum of the given numbers:30
The difference between the given numbers:10
The product of the given numbers:200

在上述程序中,创建My_Calculation类的一个对象后,将在其中创建父类成员的副本,因此子类的对象可以访问父类的成员。

父类的变量可以保存子类对象,但是使用该变量只能访问父类的成员,因此,要访问两个类的成员,建议始终创建子类的变量。

如果考虑上述程序,可以按如下所示实例化该类,但是使用父类变量不能调用multiplication()方法,因为它属于子类My_Calculation。

Calculation demo = new My_Calculation();
demo.addition(a, b);
demo.Subtraction(a, b);

注意:子类继承父类的所有成员(属性、方法和嵌套类)。构造函数不是成员,因此它们不会被子类继承,但是可以从子类中调用父类的构造函数。

super关键字


super关键字类似于this关键词,以下是使用super关键字的使用场景:

  • 如果父类的成员和子类的成员有相同的名字,它被用来区分它们

  • 在子类中调用父类的构造函数。

区分成员

如果一个类继承了另一个类,并且父类的成员具有与子类相同的名称,为了区分这些成员,需要使用super关键字,如下所示。

super.variable
super.method();

例子

在给定的程序中,有 Sub_class  和 Super_class两个类,都有一个名为display()的方法,但是具有不同的实现,还有一个名为num的变量,但是具有不同的值。我们调用两个类的display()方法,并打印两个类变量num的值。

可以观察到我们使用super关键字来区分父类和子类的成员。

复制并粘贴该程序到一个名为Sub_class.java的文件中:

class Super_class {
    int num = 20;

    //超类的显示方法
    public void display() {
        System.out.println("This is the display method of superclass");
    }
}

public class Sub_class extends Super_class {
    int num = 10;

    //子类的显示方法
    public void display() {
        System.out.println("This is the display method of subclass");
    }

    public void my_method() {
        //实例化子类
        Sub_class sub = new Sub_class();

        //调用子类的display()方法
        sub.display();

        //调用超类的display()方法
        super.display();

        //打印子类的变量num的值
        System.out.println("value of the variable named num in sub class:"+ sub.num);

        //打印超类的变量num的值
        System.out.println("value of the variable named num in super class:"+ super.num);
    }

    public static void main(String args[]) {
        Sub_class obj = new Sub_class();
        obj.my_method();
    }
}

编译并执行上述代码:

javac Super_Demo
java Super

在执行程序时,将得到以下结果:

This is the display method of subclass
This is the display method of superclass
value of the variable named num in sub class:10
value of the variable named num in super class:20

调用父类构造函数


如果一个类继承了另一个类,则子类将自动获取父类的默认构造函数。

如果要调用父类的参数化构造函数,则需要使用super关键字,如下所示:

super(values);

例子

本节中给出的程序演示了使用super关键字来调用父类的参数化构造函数,该程序包含一个父类和一个子类,其中父类包含一个接受整数值的参数化构造函数,并且我们使用了super关键字来调用父类的参数化构造函数。

将以下程序复制并粘贴到名为Subclass.java的文件中:

class Superclass {
    int age;

    Superclass(int age) {
        this.age = age;
    }

    public void getAge() {
        System.out.println("The value of the variable named age in super class is: " +age);
    }
}

public class Subclass extends Superclass {
    Subclass(int age) {
        super(age);
    }

    public static void main(String args[]) {
        Subclass s = new Subclass(24);
        s.getAge();
    }
}

编译并执行上述代码:

javac Subclass
java Subclass

在执行程序时,将得到以下结果:

The value of the variable named age in super class is: 24

IS-A关系


IS-A是一种关系:这个对象是那个对象的一个类型。

让我们看看使用extends关键字实现继承:

public class Animal {
}

public class Mammal extends Animal {
}

public class Reptile extends Animal {
}

public class Dog extends Mammal {
}

现在基于以上示例,以面向对象的术语为准:

  • Animal是Mammal的父类;

  • Animal是Reptile的父类;

  • Mammal和Reptile是Animal的子类;

  • Dog是Mammal和Animal的子类。

现在,如果考虑IS-A关系,我们可以说:

  • Mammal IS-A Animal

  • Reptile IS-A Animal

  • Dog IS-A Mammal 

  • 因此:Dog IS-A Animal

通过使用extends关键字,子类将能够继承父类的所有属性,但父类的私有成员除外。

通过使用实例运算符,我们可以确保Mammal实际上是Animal。

class Animal {
}

class Mammal extends Animal {
}

class Reptile extends Animal {
}

public class Dog extends Mammal {

    public static void main(String args[]) {
        Animal a = new Animal();
        Mammal m = new Mammal();
        Dog d = new Dog();

        System.out.println(m instanceof Animal);
        System.out.println(d instanceof Mammal);
        System.out.println(d instanceof Animal);
    }
}

这将产生以下结果:

true
true
true

既然我们已经很好地理解了extends关键字,让我们来看看 implements关键字是如何用来实现IS-A关系的。

一般来说, implements 关键字被用于在类中实现接口的方法,接口不能被一个类所继承。

public interface Animal {
}

public class Mammal implements Animal {
}

public class Dog extends Mammal {
}

instanceof运算符


instanceof运算符用来检查一个类是否是另一个类的子类。

interface Animal{}
class Mammal implements Animal{}

public class Dog extends Mammal {

    public static void main(String args[]) {
        Mammal m = new Mammal();
        Dog d = new Dog();

        System.out.println(m instanceof Animal);
        System.out.println(d instanceof Mammal);
        System.out.println(d instanceof Animal);
    }
}

这将产生以下结果:

true
true
true

HAS-A关系


HAS-A这决定了某个类是否包含某个东西,这种关系有助于减少代码冗余和错误。

让我们来看一个例子:

public class Vehicle{}
public class Speed{}

public class Van extends Vehicle {
    private Speed sp;
}

这表明Van HAS-A Speed,通过为Speed设置单独的类,我们不必将属于speed的整个代码放入Van类中,这使得可以在多个应用程序中重用Speed类。

在面向对象的方法中,用户无需担心哪个对象正在执行实际工作,因此Van类向用户隐藏了实现细节。

继承类型


继承分为多继承和单继承,Java不支持多继承。这意味着一个类不能继承一个以上的类。因此以下行为是非法的:

public class extends Animal, Mammal{}

但是,一个类可以实现一个或多个接口,这帮助Java摆脱了多重继承的限制。