简体   繁体   中英

How can you enforce that a generic type is enclosed in a specific class?

I came across an interesting problem recently: I want a method in a generics-class to accept only instances of an inner class of the specified generic type only . The goal, illustrated in the following example, is that a CarInspector<CarBrand1> can only inspect driving wheels manufactured by CarBrand1 , while keeping DrivingWheel an inner class of CarMaker . Ther rationale being that I don't want the DrivingWheel be defined outside an enclosing CarMaker subclass.

This was my first approach to the problem:

public abstract class CarMaker {
    public abstract class DrivingWheel {}
}

public class CarBrand1 extends CarMaker {
    public class DrivingWheelByCarBrand1 extends DrivingWheel {}

    private final DrivingWheelByCarBrand1 drivingWheel = new DrivingWheelByCarBrand1();

    public DrivingWheelByCarBrand1 getDrivingWheel() {
        return drivingWheel;
    }
}

public class CarBrand2 extends CarMaker {
    private class DrivingWheelByCarBrand2 extends DrivingWheel {}

    private final DrivingWheelByCarBrand2 drivingWheel = new DrivingWheelByCarBrand2();

    public DrivingWheelByCarBrand2 getDrivingWheel() {
        return drivingWheel;
    }
}

public class CarInspector<T extends CarMaker> {
    public void inspect(T.DrivingWheel arg) {}
}

However, the following code compiles just fine:

    CarBrand1 c1 = new CarBrand1();
    CarBrand2 c2 = new CarBrand2();

    CarInspector<CarBrand1> carInspector = new CarInspector<>();
    carInspector.inspect(c1.getDrivingWheel());
    carInspector.inspect(c2.getDrivingWheel());

Is there a way so that the compiler throws an error or warning in the line carInspector.inspect(c2.getDrivingWheel()) ?

NOTE : this question is besides the fact that the proposed design might not be the best choice and that defining DrivingWheel as DrivingWheel<T extends CarMaker> might be more sensible; it's an interesting tangent nonetheless, and it's a design alternative I'm considering for the specific domain I'm working at.

You need to use more generics. Change the base DrivingWheel class to add a generic parameter that specifies the car brand:

public class CarInspector<T extends CarMaker> {
    public void inspect(DrivingWheel<T> arg) {}
}

I've been able to solve the issue by changing the class CarInspector to:

public class CarInspector<T extends CarMaker, U extends CarMaker.DrivingWheel> {
    public void inspect(U drivingWheel) {}
}

And then:

CarInspector<CarBrand1, DrivingWheelByCarBrand1> carInspector = new CarInspector<>();

Still, I don't know if there's a better way to do it...

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM