Express killers, part V
First example
Today we will start from short code for perceptive. Question is: Assuming that following class compiles and it throws exception during runtime, what is the class name of obj
?
public class ClassType { // obj type definition public static void main(String[] args) { Object pattern = ClassType.class; for (int i = 0; i < obj.length(); i++) { if (pattern.equals(obj)) obj += 5; else obj += -5; System.err.println(obj); } } }
If it is too hard, copy it to your IDE. It will help you find the solution.
Second example
In the second part (this time without IDE help) focus on problems with encapsulation and overwriting properties. What will be result of execution following main()
method?
public class AccessingToOverridenAttribute { public int a; public void add() { a = 10; } public static void main(String[] args) { AccessingToOverridenAttribute f = new Bar(); f.add(); System.err.println(++f.a); System.err.println(++((Bar) f).a); } } class Bar extends AccessingToOverridenAttribute { public int a = 2; public void add() { a = 5; } }
Solutions:
First example:
Key to solve this puzzle is length()
method and add
operation. First, obj can't be a table beause in the for loop method length()
is used, not length
property. It means that obj
is a reference to the object that implements length()
method. None of the primitive type wrapper (like Integer
or Double
) implements this method. However, String
does. Is it possible that obj
is type of any other class that user implements? Length()
method will not be a problem in this case, because you can implement it. However add operator would be a problem. It is only allowed for primitive types, its wrappers and String
class. Java doesn't allow operator overloading (as it is in C++). String
is also immutable class, so you can't extend it. Gathering it all together, the only possibility is that obj is a type of String
class. In addition, it can't be null as it will throw exception during the runtime.
Second example:
Fist, add()
method will be executed based on real type of object f
, not the type declaration. So the control will go to Bar
class. It means that value of a property of the base class will not be changed.
Second, f.a
execution will result in printing property based on the declared variable type, not the real object type. It will be defined in the compilation phase and it doesn't matter, that derived class declares property with the same name. It is bad practice to name the property the same as in the base class and you shouldn't allow access to this property that will allow using the construction we presented in this example.
Third, printing property by ((Bar) f).a
will follow the rule we have just explained. Compiler in the compilation phase will choose property of the derived class, because of the explicit casting.
Summary: Properties shouldn't be visible outside of the class scope and should be accessed by getters and setters. It will eliminate the problems we have just presented and allow easier debugging.
Damian,
I know that the article is over a year old, but I only discovered exPress.
In your first example you say that String is immutable, hence it cannot be extended.
It is true that String is immutable and it is also true that it cannot be extended, but former does not imply the latter.
String cannot be extended because it is final class.
It cannot be modified, because is immutable.
Other than this, good article!
Thanks!
FORMATTING FAIL
Daniel, you are completely right.