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.
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; } }
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.
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.
Source: http://www.javaexpress.pl/article/show/Express_killers_part_V