Let's go over the rules for the following games:
For instance, if you have an instance variable named x, you could cleverly create a local variable in a method with the SAME name. Now without that local variable it would be easy to get the instance variable using its simple name even from within the method. The scope of x extends into the method easily. But once you put in the local variable - poof - you have succeeded in shadowing x! Now the only way to get the instance variable is to specify "this.x" to tell it apart from your local x. (Very Wicked).
Try it with Labels! Try it with methods! You can use a method of an inner class to shadow the method of the containing class and REALLY cause confusion! Notice that you can do all this with NO inheritance involved.
When you get to the advanced stage you can try shadowing types. If you put an import package statement at the top of your class that would bring in a class named X, then at the last minute use the single-import syntax (you know - where you provide the fully qualified name of a class) then you can shadow the type X class that WOULD have been used.
It's easy and it's fun!
II. What's my Line
This is a game similar to Dark Shadows but uses mixed double declarations. The trick is to make your names so obscure that you confuse the compiler so much that it can not tell what you are talking about. If you do it correctly, the compiler will resort to the rule book to make the decision on what to do.
For instance, take any two of the following: a variable, a class name or interface name, a package declaration. Now make sure that they have the exact same name. Now use that name to invoke an action.
For instance, create a class named ABC. Now have another class that is also visible that has an instance variable and name it ABC: SomeClass ABC = new SomeClass();
Now go ahead and try to use ABC. Try using "ABC.x" and see what happens. The compiler sits there thinking - do they want a static variable named x from class ABC, or do they want the instance variable x from the object referenced by variable ABC???
HA! You have succeeded in obscuring the declaration. No way the compiler can figure it out. So it's time to go to the rules.
If you go ask the JLS Wizard (the keeper of the rules) he will say: "In these situations, the rules specify that a variable will be chosen in preference to a type, and that a type will be chosen in preference to a package. "
So, in this case, the compiler will treat ABC as the variable instead of the class type. It will decide that you want the instance variable x from the object referenced by variable ABC.
Now it's your turn. Try it with interfaces and package names, or whatever combination you prefer.
But Beware!! If you get TOO obscure - so that the compiler can not decide which one to pick, you will get compliants about being "ambiguous". So if you inherit two different variables with the same name but different types - neither one will take priority and the compiler will be very upset.
III. Hide and go Seek
This is a game that is played by Parents and their Subs and is by far the most complicated. The rules go like this. The Parent has a bunch of members including methods, static methods, instance variables and static variables. All these things might potentially be inherited by the Sub. The Sub (either a sub-class or a sub-interface depending on who is playing) tries to hide the parent's member. If he succeeds in hiding it, the Sub gets a point. If he can't hide it, the Parent gets the point.
The test for whether or not it works is this:
Of course anyone who has played this game very much realizes that the real trick to this game is making sure that you know what can be inherited and which of those can be overridden. Anything that can be inherited but can't be overridden - can be hidden.
If the Parent's member is a: | and the sub uses the same name for a: | Sub Score | Parent Score | Comments | >
static variable | static variable | +1 | Get hidden using Parent.varName | |
static variable | instance variable | +1 | Get hidden using super.varName or Parent.varName | |
instance variable | static variable | +1 | Get at hidden using super.varName | |
instance variable | instance variable | +1 | Get hidden using super.varName | |
private variable | any variable | +1 | Can't hide what you can't inherit. But of course you can still HAVE a variable with the same name - it is just not hiding anything. | |
final variable | any variable | +1 | Get hidden using super.varName |
For hiding methods things get much more complicated:
For it to compile the Subs methods must
If the Parent's member is a: | and the sub uses the same name for a: | Sub Score | Parent Score | Comments |
static method | static method | +1 | Get hidden using Parent.methodName | |
instance method | instance method | +1 | Polymorphism is not hiding | |
abstract method | any method | +1 | Polymorphism is not hiding | |
static method | instance method | 0 | 0 | Compile error. Attempting to "override" a static method with an instance method. |
instance method | static method | 0 | 0 | Compile error. Attempting to override an instance method with a static method. |
final method | static or instance method | 0 | 0 | Compile error. Final means FINAL! |
private method | Method with same return type and throws. | +1 | Can't hide what you can't inherit - you just HAVE a method with same name. | |
Final class with regular method | Can't sub-class anyway. | +1 | Can't hide what you can't inherit. | |
Constructor | Constructor | +1 | Can't hide what you can't inherit. Heck, as constructors, they couldn't even be named the same name anyway. | |
Static initializer | Static initializer | +1 | Can't hide what you can't inherit. | |
Instance initializer | Instance initializer | +1 | Can't hide what you can't inherit. |
So far the score is Subs 6 - Parents 8.
Once you get the hang of it - start trying it with inner classes. Do you REALLY know what you get because of scope and what you get because of inheritance? Now try it with inner classes that are ALSO sub-classes of the Parent. Or you could try double inheritance using interfaces. For a real challenge use sub-interfaces with inner classes. The possibilities are endless.
And the moral of all this is:
- - Interfering with Inheritance causes "hiding".
- - Interfering with Scope causes "shadowing".
- - Interfering with Namespaces causes "obscuring".
Next month (for sure) - "Stereotyping and pigeon-holing" - or "When is an Interface too tight"