I just escaped static hell after way too many hours of frustration. I write this as a map to help you escape static hell much easier than I did. As I am far from being a java guru, if you see a better way or have an issue with my methods, by all means pile in.
Because your Java program starts execution with a block something like, ‘public static main(String args) { }’ , Java sets you on the road to static hell. The experts will give you philosophical reasons why static variables and methods are wrong. I am not an expert by any means, so my reasons are plain and simple. The first reason why static is evil is static creep.
Static creep happens when you get an error that wants to to change a variable or method to static in order to resolve an error. Static is an addictive state in Java. The first two ‘public static int whatevers’ were free, but then you had to have a getter or a setter and suddenly you are on the road to static hell. Every change or addition wants to be static and when you finally try to make a constructor, you find that the word ‘new’ and the word ‘static’ don’t play well together. So you try to reduce the static and you discover the real catch, static cling!
Static cling happens when you try to fix your static filled code from the bottom up. You fix stuff until the code saves without error and then it blows up with a null from nowhere when you run it. If you are not real careful, you can easily thrash your code into meaningless gibber while chasing down and trying to comprehend where you went wrong. If every other line in your code resembles ‘system.out.println("it got past this part and x is now " + stupidValue)’ you know exactly what I mean. Once you figure out where you need to inject a proper linkage to avoid the null, unless your initial source for the linkage is clean, static creep sets right back in.
Here is a game engine example of how to escape static. This game engine consists of 6 objects; Game, GameEngine, Play, Canvas, GameLoop and GameContext. They key to escaping static is the GameContext object.
GameContext.java is how we escape from static hell. GameContext.java contains all or most of the variables and methods that would have been static. It also has all the appropriate getters and setters. The GameContext method can initialize objects and set this.whateverObject = whateverObject so that the initialized object can be referenced later. Your game might be better organized with GameContext divided out into a few similar objects but the function remains the same and the core context object can initialize and provide links to the other context objects.
Game.java is the central object passed to methods in order to link the various processes. Game has the main block in it. Game calls GameEngine.Java and passes itself and a new Play to it.
‘GameEngine.start(new Play());.’
By creating and passing Play in this manner, we have now excaped the static realm and everything else can be free of static.
GameEngine.java sets up the canvas and starts the game loop passing itself and Canvas.java to GameLoop.java.
Play.java extends Game.java and is where the engine becomes personalized to the game. If you keep the modifications and expansions of your engine as generic as possible, you can reuse it for other games you write. Ideally Play and GameContext are the two parts of the engine that bridge between the basic engine functions and your game. As you extend your game, alway keep in mind that generic additions might be more useful if added to the engine, and specific additions should remain outside the engine. Since Play.java extends GameEngine.java, generic functions can be maintained in GameEngine.java and Play.java can have the same function personalized with a ‘@Override’ in front of them. Play.java has the generalized methods for render and update that should probably point to render and update objects. Updated properly, Play is where drastic changes to the game can be made and reversed with relative ease.
Canvas.java is the graphic object and starts with ‘public class GameCanvas extends JComponent implements ComponentListener {.’ Canvas has all the listeners so Canvas is not only the object to refer to for display, it is the object to go to for interaction with the display.
GameLoop.java calls all of the background processes that make the game run. GameLoop calls a routine in Play.java to redraw everything and a routine in Play.java to update game status over and over again. A good primer on game loops can be found here, http://www.java-gaming.org/index.php?topic=24220.0
Now to string it all together all the classes that need it have a 'Game game; defined and set by either a setter or by having it passed as a parameter and set with the line ‘this.game = game;.’ The Game class has the line ‘Context context = new Context();.’
Since Play extends Game, when play runs the line ‘context.setPlay(this);.’ game.context.getWhatever()’ and ‘game.context.setWhatever()’ can pass to any objects that have the parameter game and ‘this.game = game;’ as part of the construct.
If the object you are working on is going to be large the line ‘GameContext gc = game.context;’ can make it pretty easy to access the pool of variables. Writing something like gc.getDataYouWant() to call up a value is pretty easy and an entire range of potential static errors can be evaded. All this and the Guru’s will tell you that you have avoided the slew of security, testing and philosophical issues that static variable present.