Java中的继承是指子类可以继承或获取父类的所有非私有属性和行为。继承是面向对象编程的四大特性之一,用于提高层次结构中类之间的代码可重用性。

在本教程中,我们将了解Java 支持的继承类型以及如何在应用程序中实现继承。

1. Java中的继承是什么?

在继承中,默认情况下,一个类扩展另一个类以继承其所有非私有成员。这个类称为子类或子类。子类扩展自的类称为父类或超类。

在Java中,extends关键字用于类之间的继承。

public class Parent { } public class Child extends Parent { //Child 类继承 Parent 类 } 

2.继承的实际应用

假设我们有一个Employee类。Employee类具有一些属性和方法,所有员工在组织内都必须具备。

在同一个应用程序中,还可以有其他特殊的员工,例如Manager(经理)。经理是组织的普通员工,但另外,他们还有一些其他员工没有的属性,例如下属或部下。

public class Employee { private Long id; private String firstName; private String lastName; //Getters and Setters } 
public class Manager extends Employee { private List<Employee> subordinates; public Manager(long id, String firstName, String lastName, List<Employee> subordinates) { super(id, firstName, lastName); this.subordinates = subordinates; } } 

在上述实现中,员工拥有共同的属性,如id、firstName和lastName;而经理(Manager)仅具有特殊的subordinates属性。为了继承Employee类中的所有非私有成员(在这种情况下,getter和setter方法),Manager类扩展了Employee类。

让我们验证一下Manager类是否也继承了Employee的属性。

Manager manager = new Manager(1l, "Lokesh", "Gupta", List.of(new Employee(2l, "Alex", "Dave"))); System.out.println(manager); 

程序输出:

Manager{id=1, firstName='Lokesh', lastName='Gupta', subordinates=[Employee{id=2, firstName='Alex', lastName='Dave'}]} 

显然,Manager类能够使用Employee类的属性和方法。

现在考虑一下,如果我们不使用继承。那么我们将不得不在两个类中都维护id、firstName和lastName字段。这将导致代码重复,而代码重复总是会在代码维护中造成问题

3. 继承的类型

在 Java 中,继承可以是四种类型之一——具体取决于类层次结构。

  • 单一继承
  • 多级继承
  • 层次继承
  • 多重继承

3.1. 单一继承

在单继承中,一个子类继承一个父类。上面的示例代码(Employee和Manager)是单继承的示例。

在上面的例子中,B类扩展了A类,所以B类是A类的子类。但是C扩展了B,所以B是A类的父类C。父类也是如此B,子类也是如此。

3.3. 分层继承

在层次继承中,有一个超类,并且有多个子类扩展超类

这些子类BC,D将共享从 继承的公共成员A,但它们不会知道彼此的成员。

3.4. 多重继承

在多重继承中,一个子类可以继承多个父类的行为

在图中,类D继承了类A和类B。通过这种方式,D可以继承这两个类的非私有成员。但是,在Java中,我们不能使用extends关键字来继承两个类。那么,多重继承如何实现呢?

在JDK 1.7之前,Java中是不支持多重继承的。但从JDK 1.8开始,可以通过使用带有默认方法的接口来实现多重继承。

4. 访问父类的成员

在子类中,我们可以访问父类的非私有成员。让我们看看如何访问私有成员。

4.1. 构造函数

父类的构造函数可以通过关键字调用super。只有两条规则:

  • super()必须从子类构造函数进行调用。
  • super()call 必须是构造函数内的第一个语句。
public class Manager extends Employee { public Manager() { super(); //在构造函数中必须在第一行调用 //Other statements } } 

4.2. 作用域

非私有成员字段可以在子类中继承。我们可以使用点运算符访问它们,例如manager.id。这里的id属性是从父类继承的Employee

私有成员字段必须通过公共getter 和 setter 方法访问。

Manager manager = new Manager(...); manager.getId(); manager.getFirstName(); manager.getLastName(); 

在处理父类和子类中同名的字段时,我们必须小心。请记住,成员字段不能被覆盖。具有相同名称的字段将从父类中隐藏该字段,同时通过子类访问。

在这种情况下,将根据引用类型决定访问的属性。例如,假设Employee和Manager有一个共同的属性rating。当我们调用manager. rating时,接收到的值将由引用类型决定。

class Employee { int rating = 100; } class Manager extends Employee { int rating = 200; } Manager manager = new Manager(); System.out.println(manager.rating); //200 Employee mgrEmployee = new Manager(); System.out.println(mgrEmployee.rating); //100 

在上面的示例中,即使我们两次创建Manager实例,但rating的值是不同的,因为它是从引用类型引用的。

4.3. 方法

子类可以使用this关键字直接访问父类的非私有方法。子类不能访问父类的私有方法。

在下面的示例中,Manager类能够访问toString()方法中的公共 getter 和 setter 方法。

public class Manager extends Employee { private List<Employee> subordinates; @Override public String toString() { return "Manager{" + "id=" + getId() + ", firstName='" + getFirstName() + ''' + ", lastName='" + getLastName() + ''' + ", subordinates=" + subordinates + '}'; } } 

请注意,如果父类和子类具有相同名称的非私有方法,则访问的方法将来自实际的实例类型。

class Employee { public int getRating() { return 100; } } class Manager extends Employee { public int getRating() { return 200; } } Manager manager = new Manager(); System.out.println(manager.getRating()); //200 Employee mgrEmployee = new Manager(); System.out.println(mgrEmployee.getRating()); //200 

5. 结论

让我们总结一下我们对 Java 继承的了解:

  • 继承也称为IS-A 关系。
  • 它允许子类继承父类的非私有成员。
  • 在java中,继承是通过extends关键字来实现的。
  • 从Java 8开始,您可以使用带有默认方法的接口来实现多重继承。
  • 从引用类型类访问成员字段。
  • 成员方法是从实际实例类型访问的。