That is a pretty broad question. I think your options with Java are similar to most other languages.
You can provide a tool (like a level editor, etc) that allows people to make modifications, although that can be a fairly complex task to develop in and of itself.
Another option is to take a data driven approach. For instance, use external configuration files rather than hard coding values. If you want to take this to the extreme, then you can use the Properties Pattern (Steve Yegge has a pretty good description of it
). You essentially store everything in hash maps rather than fields.
So you don't have a Ship class any more. Everything is a bag of properties. This can give a lot of freedom to specify all sorts of behavior outside of your code.
The down sides of the approach are that the performance may not be as great, it can get unwieldy to program (lots of getValue("hitPoints")
, and you can't take advantage of the static type checking that Java gives you. If your property is maxHealth and you call it maxhealth, you won't know until run time.