5

I have a class called "Module"

public abstract class Module {

    protected Map<String, Port> ports;

    ...

    public Map<String, Port> getPorts() {
        return ports;
    }
}

and a class called Design that is a subclass of Module

public class Design extends Module{
    ...

    //want to do this but doesn't compile
    @override
    public Map<String, Port> getPorts() {
        return (Map<String, TopPort>) ports;  //TopPort is a subclass of Port
    }
}

Basically what I want to do is only add TopPorts to Design and have the type already cast upon return from the getPorts() function.

What I am doing right now is casting Ports to TopPorts after the getPorts function returns in main, but this is very finneky and someone who is building on my code would not be able to immediately understand when a TopPort is returned.

I also tried creating another function instead of overriding getPorts()

    //want to do this as well but doesn't compile
    public Map<String, TopPort> getTopPorts() {
        return (Map<String, TopPort>) ports;  //TopPort is a subclass of Port
    }

What is the correct way to do this?


More specific problem

I have been playing around with the code and I am able to add this in my "Design" class:

public TopPort getTopPortByName(String porName) {
    return (TopPort) ports.get(porName);
}

public void addPort(TopPort port) {
    this.ports.put(port.getName(), port);
}

However whenever I try to do this casting, it doesn't work:

return (Map<String, TopPort>) this.ports;

Why does the type-cast not work on the whole map even though it works on each of its members?

mohsaied
  • 2,066
  • 1
  • 14
  • 25
brinz
  • 55
  • 1
  • 6
  • Why don't you add another Map of "TopPorts" in "Design"? – mohsaied Dec 12 '14 at 03:58
  • That's a viable solution, but I want to keep the abstraction and meaning of the "Module" and "Design" classes. Design also contains Ports, but they are a special kind of Ports called TopPorts – brinz Dec 12 '14 at 04:01
  • 1
    To follow up on the idea from @mohsaied, is there an viable conversion from a `Port` instance into a `TopPort` instance that never fails? – rchang Dec 12 '14 at 04:02
  • whenever I add a "Port" to an instance of "Design", it is always a "TopPort". So the true type (don't know if that's a real term) of Ports inside Design are **always** TopPorts. That's why I can cast them after the method returns in main and I do not get a runtime error. I am just at a loss as to how I can do this inside the class to abstract away this type-casting. – brinz Dec 12 '14 at 04:11

1 Answers1

3

You'd need to make your class generic.

public abstract class Module<P extends Port> {

   protected Map<String, P> ports;

   public Map<String, P> getPorts() {
      return ports;
   }
}


class Design extends Module<TopPort> { }

I'm not sure if this isn't overkill here, though.

Thilo
  • 257,207
  • 101
  • 511
  • 656
  • Thanks, I haven't thought of that at all! It is kind-of overkill though. There are many other subclasses of Module, and a lot of code that depends on it. Changing it to a generic might force me to do a lot of refactoring. It's only in the "Design" class do I want to do this.@Thilo – brinz Dec 12 '14 at 04:14
  • 1
    Re: Refactoring: Minimum change would be to change all the `extends` clauses in your subclasses to include ``. That won't break code that uses them. – Thilo Dec 12 '14 at 04:22
  • Oh I see, this might be worth doing then.. Can you review my more specific question though? It seems that the main problem is with the typecast of a Map. Do you know why that doesn't work? @Thilo thanks – brinz Dec 12 '14 at 04:29
  • That's a different question. And it has been asked before, I'll try to find a link for you. – Thilo Dec 12 '14 at 04:31
  • There you go: http://stackoverflow.com/questions/3246137/java-generics-cannot-cast-listsubclass-to-listsuperclass – Thilo Dec 12 '14 at 04:33
  • Oh sorry for asking again. Thank you for all your help with this. @Thilo – brinz Dec 12 '14 at 04:33