继承是OOP(面向对象编程)的关键功能之一,它使我们能够从现有类中定义一个新类。例如,
class Animal
{
// eat() method
// sleep() method
}
class Dog extends Animal
{
// bark() method
}
在Java中,我们使用extends
关键字从类继承。在这里,我们从Animal类继承了Dog类。
动物是超类(父类或基类),而狗是子类(子类或派生类)。子类继承超类的字段和方法。
是关系
继承是is-a的关系。仅在两个类之间存在is-a关系时才使用继承。
这里有些例子:
- 汽车就是车辆。
- 橙色是一种水果。
- 外科医生是医生。
- 狗是动物。
示例1:Java继承
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
方法和字段。受保护的成员可以访问
- 从班级内部
- 在其子类中
- 在同一包装内
这是可以访问访问修饰符的摘要。
Class | Package | subclass | World | |
---|---|---|---|---|
public | Yes | Yes | Yes | Yes |
private | Yes | No | No | No |
protected | Yes | Yes | Yes | No |
示例2:受保护的关键字
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
类内部的type
字段受到保护。我们已经使用以下方法从Main
类访问了此字段:
dog1.type = "mammal";
这是可能的,因为Animal
类和Main
类都在同一包中(同一文件)。
Java方法覆写
从上面的示例中,我们知道子类的对象也可以访问其超类的方法。
如果同样的方法在超类和子类都定义 W¯¯ 帽子会怎样?
好吧,在这种情况下,子类中的方法将覆盖超类中的方法。例如,
示例3:方法重写示例
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
关键字。
示例4:超级关键字
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中实现多重继承。我们将在后面的章节中了解接口。
为什么要使用继承?
- 最重要的用途是代码的可重用性。父类中存在的代码无需在子类中再次编写。
- 通过方法重写实现运行时多态。在后面的章节中,我们将学习有关多态的更多信息。