Java中的继承
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. 分层继承
在层次继承中,有一个超类,并且有多个子类扩展超类。
这些子类B
, C
,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开始,您可以使用带有默认方法的接口来实现多重继承。
- 从引用类型类访问成员字段。
- 成员方法是从实际实例类型访问的。