8

Access subclass methods stored in Java superclass (downcasting?)

 3 years ago
source link: https://www.codesd.com/item/access-subclass-methods-stored-in-java-superclass-downcasting.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Access subclass methods stored in Java superclass (downcasting?)

advertisements

I'm working on an inventory program in Java. I have each object in the inventory stored as a relavent class type in a DefaultListModel and JList for each location; for example, if I have a video called "Mulan" and a generic thing called "Ball" in a location "Dorm", in the JList called "Dorm", "Mulan" will be an instance of video and "Ball" will be an instance of thing. All the classes are inherited from thing.

I'm trying to do something like this...

Dorm.getSelectedValue().methodInVideoOrThing;

...but when I try it, it says:

error: cannot find symbol
      Dorm.getSelectedValue().methodInVideoOrThing();
                             ^
symbol:   method methodInVideoOrThing()
location: class Object

Because the DefaultListModel stores each object in a generic object variable, I'm not able to access the methods for any of the classes I made. I tried this...

class c = Dorm.getSelectedValue().getClass();
c A = (c) Dorm.getSelectedValue();
A.methodInC;

... but it returned the following error:

error: cannot find symbol
      c A = (c) Dorm.getSelectedValue();
      ^
symbol: class c

error: cannot find symbol
      c A = (c) Dorm.getSelectedValue();
             ^
2 errors
symbol: class c

I know I could just cycle through all the classes using isInstanceOf and downcast on a case by case basis, but that would be quite tedious. Plus, when I do...

System.out.println(Dorm.getSelectedValue().getClass());

...it returns either class video or class thing, depending on whether "Ball" or "Mulan" is selected, so I know that java knows what class it is.

So, is there some way I can access the methods of a subclass, when that subclass is stored as a variable of type object, without downcasting? Or is there a way to do this with downcasting and I'm just doing it wrong?


The issue here is with your Object Oriented design. What kind of method is "methodInVideoOrThing()"? If this is a method that all things (including video's) have in common then it belongs in Thing. If it is a video-specific method then it belongs in Video.

In the first case (method of Thing) you can just cast the value from JList to Thing and you're done:

Thing selectedThing = (Thing) dorm.getSelectedValue();
selectedThing.methodInThing();

In the second case (method of Video) you have the problem you described of having to distinguish between different categories of Things like Videos, Fruit and Clothing. What I think I would do in this case is create separate classes to handle each category and pass the Object to it based on its category, a simple example:

public interface Handler {
    public Class getCategory();
    public void handle(Thing item);
}

public class VideoHandler implements Handler {
    public Class getCategory() {
        return Video.class;
    }

    public void handle(Thing item) {
        if (!item instanceof getCategory()) {
            throw new IllegalArgumentException("Wrong category - can only handle Video");
        }
        Video video = (Video) item;
        // do video-things
    }
}

In your calling class you need to select the correct handler based on the category:

private void init() {
    List<Handler> handlers = new ArrayList<Handler>();
    handlers.add(new VideoHandler());
    // add other handlers
}

public void someMethod(Jlist dorm) {
    Object item = dorm.getSelectedValue();
    for(Handler handler : handlers) {
        if (item instanceof handler.getCategory()) {
            // optionally catch IllegalArgumentException here
            handler.handle(item);
        }
    }
}

This can be made a bit nicer, for example use an enum as Category instead of the class, use generics to type the Handler and extract any common behavior (like the typechecking) into an abstract class, but this is the gist of it.


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK