我在AP计算机科学的练习中遇到了这个问题:
考虑下面的接口和类声明。以下哪项可用于替换/* expression */,以便getTotalMileage返回车队中所有车辆的总行驶里程?
public interface Vehicle
{
/** @return the mileage traveled by this Vehicle */
double getMileage();
}
public class Fleet
{
private List<Vehicle> myVehicles;
/** @return the mileage traveled by all vehicles in this Fleet */
public double getTotalMileage()
{
double sum = 0.0;
for (Vehicle v : myVehicles)
{
sum += /* expression */;
}
return sum;
}
// There may be instance variables, constructors, and methods are not shown.
}
选项:(a)v.getMileage()
(b)getMileage(v)
(c)Vehicle.get(v).getMileage()
(d)myVehicles.get(v).getMileage()
(e)此代码将无法编译,因为无法从List接口引用变量调用任何方法。
列表myVehicles存储车辆类型的对象,对吗?
如果是的话,运行这个程序时不应该有编译时错误吗?因为我们正在创建Vehicles类型的对象,它是一个接口。
4条答案
按热度按时间4nkexdtk1#
这被称为多态性。https://en.wikipedia.org/wiki/Polymorphism_(computer_science)
列表不必指定具体类型,但可以包含实现Vehicle的任何类型(类)。
所以在这种情况下如果你上课
您可以将宝马或福特都添加到
List<Vehicle>
当迭代
vehicles
时,getMileage()
方法将调用特定示例类的方法。gojuced72#
这是完全允许的,并且在生产代码中很常见。在任何时候,代码都不要求您“直接”示例化接口;相反,列表包含实现
Vehicle
接口的对象。因此,问题的正确答案是(a):
v.getMileage()
。关键的见解是,您并不特别关心您被赋予了什么样的载体--您所关心的只是所讨论的对象“承诺”它实现了getMileage()
方法。这样做的能力对于一些设计模式是至关重要的,比如Factory pattern,其中工厂方法的返回类型将是接口或基类。
这也常用于自动化测试中,在自动化测试中,您可能希望将某些组件替换为特定版本的组件。如果组件与外部组件(例如Web服务)交互,情况尤其如此。例如,我使用了一个名为Moq的库,它允许您轻松地创建用于测试的“假”接口实现。
whhtz7ly3#
注意这一点非常重要:
//可能有示例变量、构造函数和方法未显示。
虽然你正确地认为
new Vehicle()
不是法律的的声明,但问题中的这条注解允许添加如下代码:然后可以将
new Car(10.0)
的结果添加到车队中。(If如果你担心一个类不是“一个示例变量、构造函数或方法”,那么你可以通过引用任何不带参数并返回double的方法来“实现”
Vehicle
。)因此,正确答案是“(a),
v.getMileage()
”。7vux5j2d4#
在Java中,不是不可能创建接口类型的对象吗?
这是真的,但没有人说你不能创建接口的示例。还要注意Java有匿名类型(参见How are Anonymous inner classes used in Java?),所以完全可以创建一个实现接口的对象而不(显式)声明类:
从Java 8开始,它甚至可以缩短为: