在Java中,不是不可能创建接口类型的对象吗?

svdrlsy4  于 2023-04-28  发布在  Java
关注(0)|答案(4)|浏览(146)

我在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类型的对象,它是一个接口。

4nkexdtk

4nkexdtk1#

这被称为多态性。https://en.wikipedia.org/wiki/Polymorphism_(computer_science)
列表不必指定具体类型,但可以包含实现Vehicle的任何类型(类)。
所以在这种情况下如果你上课

class BMW implements Vehicle { //implement getMileage() method }
class Ford implements Vehicle { //implement getMileage() method }

您可以将宝马或福特都添加到List<Vehicle>

List<Vehicle> vehicles = new ArrayList<>();
vehicles.add(new BMW());
vehicles.add(new Ford());

当迭代vehicles时,getMileage()方法将调用特定示例类的方法。

gojuced7

gojuced72#

这是完全允许的,并且在生产代码中很常见。在任何时候,代码都不要求您“直接”示例化接口;相反,列表包含实现Vehicle接口的对象。
因此,问题的正确答案是(a):v.getMileage()。关键的见解是,您并不特别关心您被赋予了什么样的载体--您所关心的只是所讨论的对象“承诺”它实现了getMileage()方法。
这样做的能力对于一些设计模式是至关重要的,比如Factory pattern,其中工厂方法的返回类型将是接口或基类。
这也常用于自动化测试中,在自动化测试中,您可能希望将某些组件替换为特定版本的组件。如果组件与外部组件(例如Web服务)交互,情况尤其如此。例如,我使用了一个名为Moq的库,它允许您轻松地创建用于测试的“假”接口实现。

whhtz7ly

whhtz7ly3#

注意这一点非常重要:
//可能有示例变量、构造函数和方法未显示。
虽然你正确地认为new Vehicle()不是法律的的声明,但问题中的这条注解允许添加如下代码:

final class Car implements Vehicle {
  private final double mileage;
  Car(double mileage) {
    this.mileage = mileage;
  }
  public double getMileage() {
    return mileage;
  }
}

然后可以将new Car(10.0)的结果添加到车队中。
(If如果你担心一个类不是“一个示例变量、构造函数或方法”,那么你可以通过引用任何不带参数并返回double的方法来“实现”Vehicle。)
因此,正确答案是“(a),v.getMileage()”。

7vux5j2d

7vux5j2d4#

在Java中,不是不可能创建接口类型的对象吗?
这是真的,但没有人说你不能创建接口的示例。还要注意Java有匿名类型(参见How are Anonymous inner classes used in Java?),所以完全可以创建一个实现接口的对象而不(显式)声明类:

Vehicle myVehicle = new Vehicle() {
  @Override
  public double getMileage() {
    return 199879.5;
  }
};

从Java 8开始,它甚至可以缩短为:

Vehicle myVehicle = () -> 199879.5;

相关问题