面试题答案
一键面试Java抽象类在继承体系中的角色
- 作为通用的基类:抽象类为一组相关的子类提供了一个通用的基类框架。它定义了这些子类共有的属性和方法,子类通过继承抽象类来获得这些特性,并在此基础上进行扩展和实现。例如,在图形绘制的继承体系中,可以有一个抽象类
Shape
,它为Circle
、Rectangle
等具体图形类提供通用的属性(如颜色)和方法(如计算面积的抽象方法)。 - 定义规范和约束:抽象类中可以包含抽象方法,这些方法只有声明没有实现。子类必须实现这些抽象方法,从而保证了整个继承体系中行为的一致性。比如,
Shape
抽象类中定义了抽象方法draw()
,所有继承自Shape
的子类(如Circle
、Rectangle
)都必须实现draw()
方法,以实现具体的绘制逻辑。 - 避免实例化:抽象类不能被实例化,它存在的意义主要是为子类提供一个统一的抽象概念,强制子类按照其定义的规范进行扩展。这有助于确保继承体系的合理性和规范性。
设计抽象类时遵循的原则
- 单一职责原则:抽象类应该有且仅有一个引起它变化的原因。即抽象类应该专注于一个特定的功能领域或概念,这样可以使抽象类的职责清晰,易于维护和扩展。例如,
Shape
抽象类只专注于图形相关的属性和行为,不应该混入与图形无关的功能,如文件读写操作。 - 开闭原则:对扩展开放,对修改关闭。抽象类应该设计得易于子类进行扩展,同时尽量避免在子类扩展时对抽象类本身进行修改。通过在抽象类中定义抽象方法,让子类去实现这些方法来满足不同的需求,从而实现对扩展开放。而抽象类本身的核心逻辑和结构保持稳定,实现对修改关闭。
- 里氏替换原则:子类对象能够替换其基类对象,且不会破坏程序的正确性。这意味着抽象类定义的行为和约束,子类必须能够完全遵循。例如,如果
Shape
抽象类定义了获取面积的方法getArea()
,那么所有Shape
的子类(如Circle
、Rectangle
)实现的getArea()
方法应该返回合理的面积值,以保证在任何使用Shape
对象的地方,都可以用其子类对象替代。
示例代码
// 抽象类
abstract class Animal {
// 抽象类的属性
protected String name;
// 抽象类的构造函数
public Animal(String name) {
this.name = name;
}
// 抽象方法
public abstract void makeSound();
// 具体方法
public void eat() {
System.out.println(name + " is eating.");
}
}
// 子类继承抽象类
class Dog extends Animal {
public Dog(String name) {
super(name);
}
// 实现抽象方法
@Override
public void makeSound() {
System.out.println(name + " barks.");
}
}
// 子类继承抽象类
class Cat extends Animal {
public Cat(String name) {
super(name);
}
// 实现抽象方法
@Override
public void makeSound() {
System.out.println(name + " meows.");
}
}
在上述示例中,Animal
是一个抽象类,它定义了name
属性、eat()
具体方法以及抽象方法makeSound()
。Dog
和Cat
类继承自Animal
,并实现了makeSound()
方法,遵循了抽象类定义的规范。