简体   繁体   中英

How to return an actual instance from a method with a generic return type

I'm having hard time with creating a type safe behavior, I'll use a general example in order to emphasize my issue:

I have an interface BoxCreator which is defined by:

public interface BoxCreator{
    public Box create(int id ,List<Box> others);
}

and a general Box class (A Box can contain several other Box es) which has methods like int getId() , Box getInternalBox(int id) .

Suppose I have a class Shed implements BoxCreator,Container (where container is just a general interface with action like add and remove ). I can put new things inside the shed and it'll box them in a ShedBox which implements Box .

So far so good, the problem arises when I try to make some other class that will do things a little differently, for example CoolShed extends Shed implements BoxCreator which will put thing into CoolBox es (which extend ShedBox ).

For now it works but I have several down-casts in the CoolShed class (from a general Box to CoolBox ) that might be 'not pretty'.

What I'm looking for is a way to make

Shed<T extends ShedBox> implements BoxCreator<T>

And then when implemeting the CoolShed I'd just do something like

CoolShed extends Shed<CoolBox> implemets BoxCreator<CoolBox>

I was trying to make the various classes generic but but couldn't create a generic create method because I can't instantiate a T or return one for that matter. So I'm a little lost.

Several notes:

  1. The CoolShed uses a lot of the Shed logic but I'd just to make it use the CoolBox class as a container.
  2. Currently the Shed has an instance of a BoxCreator so when creating CoolShed I just make CoolShed the new creator and it works.
  3. CoolShed will only have CoolBox instances but I wouldn't really mind anything extending ShedBox in the Shed class.

I just couldn't find a good explanation of how to achieve the desired behavior nor I could tell whether my existing casts are OK

I know my example is quite long I'd be happy to make it clearer in any way I can.

EDIT

A code template to make the question clearer:

public interface BoxCreator{
    public Box create(int id ,List<Box> others);
}

public interface Box{
    void put()
    void addAnother(Box box);
}

public class ShedBox implements Box{
    void put()
    void addAnother(Box box);
}

public class CoolBox extends ShedBox{ //has some extra features but moslty the same
    void put()
    void addAnother(Box box);
}

public interface Container {
    Box addValue(int value);
    Box getBox(int id);
    .
    .
}

public class Shed implements Container, BoxCreator {
    BoxCreator creator;
    SomeCollection<Box> boxes;
    Shed(){
        creator = this;
        .
        .
        .
    }

    Box addValue(int id){
        .
        .//some logic to get otherBox here
        .
        Box box = creator.createBox(id,otherBox);
    }

    Box getBox(int id);

    public Box create(int id ,Box other){
        return new ShedBox(id,others)
    }
}

public class CoolShed extends Shed implements BoxCreator {

    CoolShed(){
        creator = this;
        .
        .
        .
    }

    addValue(int id){
        Box boxAdded = super.add(id)
        .
        .
        .
        CoolBox box = (CoolBox)boxAdded; // The questionable cast
        .
        . //Some logic that involves CoolBox specific actions 
        .
    }

    public Box create(int id ,Box other){
        return new CoolBox(id,others)
    }

}

(Previous answer removed)

EDIT: This solution should be better, assuming others may contain any box:

public interface BoxCreator {
    public Box create(int id, List<Box> others);
}
public class Shed implements BoxCreator {
    @Override
    public ShedBox create(int id, List<Box> others) {
        ...
    }
}
public class CoolShed extends Shed {
    @Override
    public CoolBox create(int id, List<Box> others) {
        ...
    }
}

Also, don't do this:

BoxCreator creator;
creator = this;
creator.create(...);

Instead, you should either write this.create(...) or simply create(...) . Then you won't have to cast from Box to the desired subclass, since the value returned from create will already be of type ShedBox or CoolBox .

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