在本教程中,我们将借助示例学习Java中的继承。
继承是OOP(面向对象编程)的重要功能之一,它使我们能够从现有类中定义一个新类。例如,
class Animal { // eat() 方法 // sleep() 方法 } class Dog extends Animal { // bark() 方法 }
在Java中,我们使用extends关键字从类继承。在这里,我们从Animal类继承了Dog类。
Animal是超类(父类或基类),而Dog是子类(子类或派生类)。 子类继承超类的字段和方法。
继承是is-a关系,只有当两个类之间存在is-a关系时,我们才使用继承。
这里有些实例:
汽车就是车辆。
橙色是一种水果。
外科医生是医生。
狗是动物。
class Animal { public void eat() { System.out.println("I can eat"); } public void sleep() { System.out.println("I can sleep"); } } class Dog extends Animal { public void bark() { System.out.println("I can bark"); } } class Main { public static void main(String[] args) { Dog dog1 = new Dog(); dog1.eat(); dog1.sleep(); dog1.bark(); } }
输出结果
I can eat I can sleep I can bark
在这里,我们从父类Animal继承了Dog的子类。 Dog类从Animal类继承了eat()和sleep()方法。
因此,Dog类的对象可以访问Dog类和Animal类的成员。
我们在先前的教程中了解了private和public访问修饰符。
private 成员只能在类内访问
public 成员可以从任何地方访问
您还可以设置方法和字段为protected,受保护的成员可以访问
类内部
在其子类中
在同一包内
这是可以访问访问修饰符的摘要。
修饰符 | 类 | 包 | 子类 | 全局 |
---|---|---|---|---|
public | Yes | Yes | Yes | Yes |
private | Yes | No | No | No |
protected | Yes | Yes | Yes | No |
class Animal { protected String type; private String color; public void eat() { System.out.println("I can eat"); } public void sleep() { System.out.println("I can sleep"); } public String getColor(){ return color; } public void setColor(String col){ color = col; } } class Dog extends Animal { public void displayInfo(String c){ System.out.println("I am a " + type); System.out.println("My color is " + c); } public void bark() { System.out.println("I can bark"); } } class Main { public static void main(String[] args) { Dog dog1 = new Dog(); dog1.eat(); dog1.sleep(); dog1.bark(); dog1.type = "mammal"; dog1.setColor("black"); dog1.displayInfo(dog1.getColor()); } }
输出结果
I can eat I can sleep I can bark I am a mammal My color is black
在这里,Animal类中的类型字段受到保护。我们已经从Main类访问了这个字段
dog1.type = "mammal";
这是可行的,因为Animal和Main类都在同一个包(同一个文件)中。
从上面的示例中,我们知道子类的对象也可以访问其超类的方法。
如果在超类和子类中都定义了相同的方法,会发生什么情况?
好吧,在这种情况下,子类中的方法将覆盖超类中的方法。例如,
class Animal { protected String type = "animal"; public void eat() { System.out.println("I can eat"); } public void sleep() { System.out.println("I can sleep"); } } class Dog extends Animal { @Override public void eat() { System.out.println("I eat dog food"); } public void bark() { System.out.println("I can bark"); } } class Main { public static void main(String[] args) { Dog dog1 = new Dog(); dog1.eat(); dog1.sleep(); dog1.bark(); } }
输出结果
I eat dog food I can sleep I can bark
在这里,eat()同时出现在超类Animal和子类Dog中。我们创建了子类Dog的对象dog1。
当我们使用dog1对象调用eat()时,将调用Dog内部的方法,而不调用超类的相同方法。这称为方法重写。
在上面的程序中,我们使用了@Override 注释来告诉编译器我们正在重写方法。但是,这不是强制性的。在下一个教程中,我们将详细了解方法重写。
如果需要从Animal的子类调用eat()方法,则使用super关键字。
class Animal { public Animal() { System.out.println("I am an Animal"); } public void eat() { System.out.println("I can eat"); } } class Dog extends Animal { public Dog(){ super(); System.out.println("I am a dog"); } @Override public void eat() { super.eat(); System.out.println("I eat dog food"); } public void bark() { System.out.println("I can bark"); } } class Main { public static void main(String[] args) { Dog dog1 = new Dog(); dog1.eat(); dog1.bark(); } }
输出结果
I am an Animal I am a dog I can eat I eat dog food I can bark
在这里,我们使用了super关键字通过super()来调用构造函数。 另外,我们使用super.eat()调用Animal超类的eat()方法。
注意:调用构造函数和super方法时使用的区别。要了解更多信息,请访问Java super关键字。
继承有五种类型。
单一继承 - B类A仅从类继承。
多级继承 - B类从A类继承,然后C类从B类继承。
分层继承 - A类作为B,C和D父类。
多重继承 -类C从接口A和扩展B。
混合继承 -两种或多种继承的混合。
Java不支持通过类的多重继承和混合继承。但是,我们可以通过接口在Java中实现多重继承。我们将在后面的章节中了解接口。
最重要的用途是代码的可重用性。父类中存在的代码无需在子类中再次编写。
通过方法重写实现运行时多态。在后面的章节中,我们将学习有关多态的更多信息。