面向对象是Java语言的核心,在Java中所有的类都继承于 java.lang.Object。当一个类没有显式使用继承的两个关键字(extends, implements),则默认继承 Object类。面向对象是现代软件设计模式的基础。合理利用它,不仅可以增强代码的可扩展性和复用性,同时也提高开发效率和降低维护成本。关于面向对象的详细介绍,请参考我的另一篇文章“面向对象编程详解”。
这篇文章主要介绍Java的面向对象编程特性。
继承
继承就是子类继承父类的特征和行为,使得子类具有父类相同的行为和数据结构。
语法格式
类的继承:extends关键字
// 顶层交通工具父类
public class Vehicle {
}
// Car使用extends关键字继承了Vehicle
// 轿车是交通工具的子类
public class Car extends Vehicle {
}
实现接口:implements关键字
// 可载人接口,所有的客车要可以实现这个接口来具备可载人的行为
public interface PeopleCarrier {
}
// 公共汽车实现了可载人接口
public class Bus implements PeopleCarrier{
}
特性
- 仅支持单继承,即一个类只能继承一个类;但是可以实现多个接口,或接口与类混合的继承模式。例如:
// Car继承了Vehicle父类,同时又实现了3个接口,代表轿车具有载人、交税和陆地驾驶的行为
public class Car extends Vehicle implements PeopleCarrier, Taxable, DirveOnRoad {
}
- 子类拥有父类的非私有(用private修饰的)成员变量和方法;子类可以添加自己的成员变量和方法,来扩展父类的行为特征:
public class Vehicle {
// 所有Vehicle共有的方法
public void dirve() {
System.out.println("Let's have a ride!");
}
}
public class Car extends Vehicle implements PeopleCarrier, Taxable, DirveOnRoad {
// Car自己的方法
public void changeGear() {
System.out.println("Let's change gear");
}
}
public class UseVehicle {
public void dirveVehicle() {
// Car对象具有父类Vehicle的drive()方法和Car的changeGear()方法
Car car = new Car();
car.dirve();
car.changeGear();
}
}
- 子类可以重写父类的方法,详见本文“方法重写”部分
- 支持多重继承,例如 B 类继承 A 类,C 类继承 B 类,所以按照关系就是 B 类是 C 类的父类,A 类是 B 类的父类。那么C同时具有B和A的行为,B具有A的行为:
// 继承了Car类
public class HybridCar extends Car{
public void chargePower() {
}
}
public class UseVehicle {
public void dirveVehicle() {
// HybridCar的对象具有父类Vehicle,Car的行为,同时也有自己的方法
HybridCar hybridCar = new HybridCar();
hybridCar.dirve();
hybridCar.changeGear();
hybridCar.chargePower();
}
}
super和this
通过super关键字来访问父类成员,用来引用当前对象的父类实例;this是对自己的引用;
public class Vehicle {
public void dirve() {
System.out.println("Drive");
}
}
public class Truck extends Vehicle {
public void drive() {
System.out.println("Drive truck");
}
public void driveBoth() {
this.drive();
super.dirve();
}
}
public class UseVehicle {
public void dirveVehicle() {
Truck truck = new Truck();
truck.driveBoth();
}
}
// 输出结果为:
Drive truck
Drive
在子类没有覆盖父类方法的情况下,super和this关键字通常是会省掉的。这样调用者就会自动引用子类或父类的方法。例如,上面的例子,如果把Truck的dirve()改名为driveTruck(),driveBoth()方法就可以完全省掉super和this关键字:
public class Truck extends Vehicle {
// 改名为driveTruck
public void driveTruck() {
System.out.println("Drive truck");
}
// 调用者就可以省掉super和this
public void driveBoth() {
driveTruck();
dirve();
}
}
final关键字
final关键字的语义是 "最终的",可以用来修饰变量(包括类属性、实例属性、局部变量和形参)、方法(包括类方法和实例方法)和类。
使用 final 关键字声明类,就是把类定义定义为最终类,不能被继承;如果用于修饰方法,该方法不能被子类重写:
public class Vehicle {
public final void calculateTax() {
}
}
public class Car extends Vehicle {
// 编译报错,无法重写final修饰的父类方法
public void calculateTax() {
}
}
构造函数
子类必须调用父类的构造函数,但不是继承父类的构造函数,而是通过隐式或显式调用父类构造函数来满足继承关系。子类调用父类构造函数的规则是:
如果父类有默认构造函数(无参数),子类可以不显式调用;Java会自动调用父类的默认构造函数;
如果父类定了有参数构造函数(未使用默认构造函数),子类必须在构造函数中显式调用父类构造函数;
如果父类既定义了无参和有参构造函数,子类可以选择不调用父类构造函数,Java自动调用无参构造函数;子类也可以显式调用有参构造函数;
public class Vehicle {
private String model;
Vehicle() {
}
Vehicle(String model) {
this.model = model;
}
}
// 显式调用有参构造函数
public class Truck extends Vehicle {
Truck() {
super("GSL-6");
}
}
// 隐式调用无参构造函数,也可以显式调用
public class Bus extends Vehicle {
Bus() {
}
Bus(String model) {
super(model);
}
}
方法重写
子类可以重写父类的方法,改变父类的行为。子类根据自己的需要重新实现父类提供的方法,满足更具体的业务逻辑。利用方法重写可以实现灵活的对象间状态转化,即多态。
重写的方法必须与父类方法有一样的名字、形参和返回值类型。
public class Vehicle {
void drive() {
System.out.println("Can drive");
}
}
public class Bus extends Vehicle {
// 重写drive方法
void drive() {
System.out.println("Can drive bus");
}
}
public class UseVehicle {
public void dirveVehicle() {
Vehicle vehicle = new Vehicle();
vehicle.drive();
Bus bus = new Bus();
bus.drive();
}
}
打印结果:
Can drive
Can drive bus
方法重写的规则如下:
- 子类的方法与重写的方法形参必须完全一致;
- 返回类型与被重写方法的返回类型可以不相同,但是必须是父类方法返回值的子类;
- 访问权限不能比父类中被重写的方法的访问权限更低。例如:如果父类的一个方法被声明为 public,那么在子类中重写该方法就不能声明为 protected;
- 声明为 final 的方法不能被重写;声明为 static 的方法不能被重写,但是能够在子类中被再次声明;
- 如果子类和父类在同一个包中,除了被private 和 final 方法,子类可以重写父类所有方法;
- 如果子类和父类不在同一个包中,那么子类只能够重写父类的声明为 public 和 protected 的非 final 方法;
可以在子类的方法中用super()引用父类的被重写的方法。
以上就是对Java基础类的继承的相关介绍,希望老贾的这篇文章能帮到大家。