1

I am trying to write a screen manager in Java - a language I am new to. This class (ScreenManager) should be able to take a class type and then instantiate it. It's easier to explain with code so, I want to be able to do this:

ScreenManager manager = new ScreenManager();
manager.setCurrentScreen(MenuScreen.class);
manager.runScreen();

MenuScreen extends a class called Screen which extends JFrame. My idea is to have AScreen, BScreen, CScreen etc all extend Screen so I can cast them to Screen and store them as one single type.

So ScreenManager is like this:

import javax.swing.UIManager;

public class ScreenManager {

    private Class<Screen> _currentScreen;
    private Screen _currentScreenObject;

    public ScreenManager() { }

    public ScreenManager(Class<Screen> screen) {
        setCurrentScreen(screen);       
    }

    public Class<Screen> getCurrentScreen() {
        return _currentScreen;          
    }

    public void setCurrentScreen(Class<Screen> screen) {
        _currentScreen = screen;
    }

    public void runScreen() {
        if (_currentScreen == null) return;
        javax.swing.SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                UIManager.put("swing.boldMetal", Boolean.FALSE);                
                try {
                    _currentScreenObject = _currentScreen.newInstance();
                } catch (InstantiationException | IllegalAccessException e) {                   
                    e.printStackTrace();
                }
            }
        });
    }
}

Screen is simply, and all AScreen, BScreen etc have is some initialisation code in their constructors.

import javax.swing.JFrame;

public class Screen extends JFrame {

    private static final long serialVersionUID = 1L;

}

The bit I am stumbling on is passing the class type to the ScreenManager class.

ScreenManager manager = new ScreenManager();
manager.setCurrentScreen(MenuScreen.class);
manager.runScreen();

Now I can cast it like so:

Screen s = new MenuScreen();

But I can't seem to pass the class type. I've tried to cast it like so:

manager.setCurrentScreen((Screen.class)MenuScreen.class);

That doesn't work.

FYI, I come from a C# background, so my perspective may (and probably is) wrong. If so, please correct me.

Thanks for reading this far!

Adam K Dean
  • 7,387
  • 10
  • 47
  • 68
  • 3
    Why not just manager.setCurrentScreen(new MenuScreen())? – Matsemann Jun 29 '12 at 21:03
  • Yeah, that part is confusing me, too. It's rare in Java in a relatively simple application to be fussing with the actual class as opposed to instances of that class. – Marvo Jun 29 '12 at 21:04
  • I was under the impression I needed to run in with `javax.swing.SwingUtilities.invokeLater`, see this: http://stackoverflow.com/questions/6567870/what-does-swingutilities-invokelater-do – Adam K Dean Jun 29 '12 at 21:07

2 Answers2

4

Use Class<? extends Screen> instead of Class<Screen>. It will then accept both Screen.class and MenuScreen.class, given MenuScreen extends Screen. Sort of Java's equivalence to C#'s generics covariance...

Eran
  • 21,632
  • 6
  • 56
  • 89
1

Unlike C#, type parameters in Java are a compile-time-only feature and are not covariant.

In Java a List<Integer> is not a List<Number>.

You can specify "some unknown subtype of Screen" by declaring it as Class<? extends Screen>. That's the best Java can do, because it is only checking the types when it runs the compiler, not when you run the code like C# does.

Affe
  • 47,174
  • 11
  • 83
  • 83