Express killers, part IV
First, quick reminder: what will be result when you execute following code?
public class Loader { { System.out.println("a"); } X x; static { System.out.println("b"); } Loader() { System.out.println("c"); } { System.out.println("d"); } static class X { static { System.out.println("e"); } } public static void main(String[] args) { System.out.println("f"); new Loader(); } }
When we get into this piece of code we realized (surprisingly!) that it doesn't compile, but it is simple and fixing doesn't take a lot of time. However, what if we have following restrictions in code manipulation:
- It is academic example and ternary operator can't be changed (it means
main()
method can't be changed), - classes A and B are used in other projects and, besides they do nothing, API can't be changed (methods' signatures and inheritance hierarchy).
What can you do, to make this code able to compile without changing the result?
class Parent { } class A extends Parent { public boolean test() { return false; } } class B extends Parent { public boolean test() { return true; } } public class X { public static void main(String[] args) { A a = new A(); B b = new B(); boolean t = (true ? a : b).test(); } }
Results:
First example:
Result will be:
b – after class is loaded, static blocks are executed,
f – execution of main() method,
a, d – creation object of class Loader will execute subsequent (ordered by position in class) class initializations blocks,
c – execution of class constructor.
Letter e will not be printed because static inner class is loaded at the time of first usage. In above example this class is not created, so it will not be loaded as well. Even despite the fact, that it is attribute in class Loader
, because it is just type declaration and object is not created.
Second example:
Tenary operator can't be used as it is, because compiler:
- will be looking for first common super class for classes A and B,
- will check, if found class has method that is called, and if not, will return an error.
Compiler at the compile phase can't define what will be the result of the ternary operator (even though in this example, optimizer can figure out resulting type), so we have to be sure that in both cases calling method test()
will be possible.
Besides that in this example, both types have test()
method, compiler will look for common super class, so it will find Parent class, that doesn't have test()
method.
What can we do about it? If ternary operator can't be changed, it means we have to assure that Parent class has test()
method. We can do it:
- by changing
Parent
class to abstract class and add abstracttest()
method, but it will break possibility to callnew Parent()
; - by adding
test()
method to classParent
, that will throw an exception that it is not implemented yet. It means that derived classes should overwrite this method.
The best solution would be to remove ternary operator and replace it with if-else
statement. In this case modification of Parent
class will be not needed.
Nobody has commented it yet.