为接口方法Java

时间:2019-04-25 13:32:00

标签: java generics inheritance

我一直在研究Java中的泛型类和方法,并在上一篇论文中遇到了这个问题

enter image description here

我尝试实现问题中提出的接口和类,包括加油方法,但发现将Car参数作为参数传递没有问题

电动界面

public interface Motorized {

    public int getFuel();

}

车辆类

public abstract class Vehicle{

    private int fuel;

    public Vehicle(int fuel) {

        this.fuel = fuel;
    }

    public String toString(){

        return("Fuel is: " + getFuel());
    }

    public int getFuel() {

        return fuel;
    }
}

汽车课

public class Car extends Vehicle implements Motorized {

    int seats;

    public Car(int fuel, int seats) {

        super(fuel);
        this.seats = seats;
    }

    public int getSeats() {

        return seats;
    }

    @Override
    public String toString(){

        return("Fuel is: " + getFuel() + "and the car has" + getSeats() + "seats.");
    }
}

测试方法

public class VehicleTest {

    public static Motorized refuel(Motorized v) {

        return v;
    }

    public static void main(String[] args) {

        Car car = new Car(15, 5);

        System.out.println(refuel(car));
    }
}

有人可以向我解释这个问题应该是什么问题,为什么我的实现不能反映这个问题?

3 个答案:

答案 0 :(得分:2)

问题在于方法的返回值:

public static Motorized refuel(Motorized v)

您说在传递Car时没有问题,这是一个完全有效的语句。但是您尚未尝试通过refuel方法取回值:

Car car = ...
Car refueled = refuel(car); // compiler error: Motorized is not assignable to Car!

尽管Motorized的返回类型为Car extends Motorized,但您不能确定返回的Motorized实例是否总是{em> }}。请参阅以下简化示例:

Car

现在,您可能会期望得到public static Motorized refuel(Motorized v) { // try to refuel // uh oh... the gas station exploded // you have to change to a motorbike which just stands around return new Motorbike(); } ,但您会得到Car,因此即使强制转换也会失败:

Motorbike

您可以使用泛型来做到这一点:

Car refueled = (Car) refuel(car); // ClassCastException, Motorbike is not a Car

尽管如果加油站再次爆炸,则该方法将存在问题。它不知道public static <M extends Motorized> M refuel(M m) { // refuel the motorized vehicle return m; } 实际上是什么。因此,这可能是您头痛的救星。

答案 1 :(得分:1)

代替

System.out.println(refuel(car));

尝试

Car refueledCar = refuel(car);

您会发现它无法编译,因为从refuel方法获得的变量不是Car的实例,而是某种对象(但编译器不知道实现Motorized哪种对象。您可以使用

广播到Car
Car refueledCar = (Car) refuel(car);

但这很笨拙,并且使您的代码更容易出现错误。幸运的是,有更好的方法可以解决此问题。具体来说,通过使用泛型。如果将refuel的方法签名更改为此:

public static <T extends Motorized> T refuel(T t)

您会发现返回的类型与您传递的类型相同,并且编译器对以前无法编译的那一行非常满意。

通过解释的方式,新方法签名的基本含义是“存在一个未知类型T,它扩展了Motorized。该方法接受类型为T的变量,并且具有相同类型的返回值。”

答案 2 :(得分:0)

您可以为此使用generic method

这是一个极其简化的层次结构(此处Vehicle被忽略)。

interface Motorized {
    void refuel();
}
class Car implements Motorized {
    @Override
    public void refuel() {
        // TODO
    }
}

现在这是您的测试班:

class VehicleTest {
//         | generic method type parameter bound up to any `Motorized`
//         |                     | returns same type...
//         |                     |        | ... as given type
//         |                     |        |
    static <T extends Motorized> T refuel(T t) {
        t.refuel();
        return t;
    }

    // and here's some usage
    public static void main(String[] args) {
        Car car = new Car();
        Car refueled = refuel(car);
    }
}