我是 Java 编程的新手,正在尝试掌握 OOP。
所以我建立了这个抽象类:
public abstract class Vehicle{....}
和 2 个子类:
public class Car extends Vehicle{....}
public class Boat extends Vehicle{....}
Car
和 Boat
还包含一些不常见的独特字段和方法(名称不同,所以我无法定义抽象方法为他们在车辆中)。
现在我在 mainClass 中设置了我的新车库:
Vehicle[] myGarage= new Vehicle[10];
myGarage[0]=new Car(2,true);
myGarage[1]=new Boat(4,600);
在我尝试访问 Car 独有的字段之一之前,我对多态性非常满意,例如:
boolean carIsAutomatic = myGarage[0].auto;
编译器不接受。我使用强制转换解决了这个问题:
boolean carIsAutomatic = ((Car)myGarage[0]).auto;
这行得通……但它对方法没有帮助,只是对字段有帮助。意思是我做不到
(Car)myGarage[0].doSomeCarStuff();
所以我的问题是 - 我的车库里到底有什么?我正在尝试获得直觉并了解“幕后”发生的事情。
为了 future 的读者,以下答案的简短摘要:
- 是的,
myGarage[]
中有一个
Car
- 作为一种静态类型语言,如果通过基于 Vehicle 父类(super class)的数据结构(例如
Vehicle myGarage[ ]
)
- 至于如何解决,主要有以下两种方法:
- 使用类型转换,这将减轻编译器的顾虑,并将设计中的任何错误留给运行时
- 我需要选角这一事实表明设计存在缺陷。如果我需要访问非车辆功能,那么我不应该将 Cars 和 Boats 存储在基于 Vehicle 的数据结构中。要么让所有这些功能都属于 Vehicle,要么使用更具体(派生)的基于类型的结构
- 在许多情况下,组合和/或接口(interface)是继承的更好替代方案。可能是我下一个问题的主题......
- 如果您确实有时间浏览答案,那么还有许多其他好的见解。
如果您需要区分车库中的 Car
和 Boat
,那么您应该将它们存放在不同的结构中。
例如:
public class Garage {
private List<Car> cars;
private List<Boat> boats;
}
然后您可以定义特定于船只或特定于汽车的方法。
那为什么会有多态呢?
假设 Vehicle
是这样的:
public abstract class Vehicle {
protected int price;
public getPrice() { return price; }
public abstract int getPriceAfterYears(int years);
}
每一个Vehicle
都有一个价格,所以它可以放在Vehicle
抽象类中。
然而,确定 n 年后价格的公式取决于车辆,所以它留给实现类来定义它。例如:
public Car extends Vehicle {
// car specific
private boolean automatic;
@Override
public getPriceAfterYears(int years) {
// losing 1000$ every year
return Math.max(0, this.price - (years * 1000));
}
}
Boat
类可能有 getPriceAfterYears
的其他定义以及特定的属性和方法。
所以现在回到 Garage
类,你可以定义:
// car specific
public int numberOfAutomaticCars() {
int s = 0;
for(Car car : cars) {
if(car.isAutomatic()) {
s++;
}
}
return s;
}
public List<Vehicle> getVehicles() {
List<Vehicle> v = new ArrayList<>(); // init with sum
v.addAll(cars);
v.addAll(boats);
return v;
}
// all vehicles method
public getAveragePriceAfterYears(int years) {
List<Vehicle> vehicules = getVehicles();
int s = 0;
for(Vehicle v : vehicules) {
// call the implementation of the actual type!
s += v.getPriceAfterYears(years);
}
return s / vehicules.size();
}
多态性的意义在于能够在 Vehicle
上调用 getPriceAfterYears
,而无需关心实现。
通常,向下转型是设计有缺陷的标志:如果您需要区分它们的实际类型,请不要将车辆全部存放在一起。
注意:当然这里的设计可以很容易地改进。只是举例说明要点。
我是一名优秀的程序员,十分优秀!