louis058
louis058

Reputation: 67

Using a bounded generic class to extend another generic class produces an unknown type

So imagine the following class hierarchy:

abstract class Train {}
class BulletTrain extends Train {}

abstract class Base<T> {}
abstract class TrainBuilder<T extends Train> extends Base<T> {}

class BulletTrainBuilder<T extends BulletTrain> extends TrainBuilder<T> {
    T getBulletTrain() {
        BulletTrain someBulletTrain;
        // Make some kind of BulletTrain and put it in someBulletTrain
        return someBulletTrain; // Compile Error: BulletTrain does not match T
    }
}

Inside getBulletTrain, it seems that no subclass of BulletTrain, or BulletTrain instance can be returned, as Java makes a compile error which states that the particular subclass (or BulletTrain itself) does not match T.

Has type information been lost somehow here?

Upvotes: 0

Views: 30

Answers (1)

Radiodef
Radiodef

Reputation: 37845

Type information hasn't been lost, it's just that from BulletTrainBuilder you can't determine that T is BulletTrain and not some subclass of it.

For example, what if I did this:

BulletTrainBuilder<FastBulletTrain> builder = ... ;

Calling getBulletTrain would try to cast a BulletTrain in to a FastBulletTrain and throw an exception.

It seems like you just want to do this:

class BulletTrainBuilder extends TrainBuilder<BulletTrain> {
    public BulletTrain getBulletTrain() { ... }
}

Otherwise, if you need to further delegate T down the hierarchy, then you can't know what it is to do something like you're trying to do. You would need to also delegate wherever someBulletTrain comes from to the subclass as well.

For example:

abstract class AbstractTrainFactory<T extends Train> {
    protected abstract T newTrainInstance();
    public abstract T fashionTrainToSpec();
}

abstract class AbstractBulletTrainFactory<T extends BulletTrain>
extends AbstractTrainFactory<T> {
    @Override
    public T fashionTrainToSpec() {
        T theTrain = newTrainInstance();
        theTrain.noseSwoop = noseSwoopSpec;
        return theTrain;
    }
}

class FastBulletTrainFactory
extends AbstractBulletTrainFactory<FastBulletTrain> {
    @Override
    protected FastBulletTrain newTrainInstance() {
        return new FastBulletTrain();
    }
}

Upvotes: 4

Related Questions