When is an interface with a default method initialized? - java

While searching through the Java Language Specification to answer this question, I learned that
Before a class is initialized, its direct superclass must be
initialized, but interfaces implemented by the class are not
initialized. Similarly, the superinterfaces of an interface are not
initialized before the interface is initialized.
For my own curiosity, I tried it and, as expected, the interface InterfaceType was not initialized.
public class Example {
public static void main(String[] args) throws Exception {
InterfaceType foo = new InterfaceTypeImpl();
foo.method();
}
}
class InterfaceTypeImpl implements InterfaceType {
#Override
public void method() {
System.out.println("implemented method");
}
}
class ClassInitializer {
static {
System.out.println("static initializer");
}
}
interface InterfaceType {
public static final ClassInitializer init = new ClassInitializer();
public void method();
}
This program prints
implemented method
However, if the interface declares a default method, then initialization does occur. Consider the InterfaceType interface given as
interface InterfaceType {
public static final ClassInitializer init = new ClassInitializer();
public default void method() {
System.out.println("default method");
}
}
then the same program above would print
static initializer
implemented method
In other words, the static field of the interface is initialized (step 9 in the Detailed Initialization Procedure) and the static initializer of the type being initialized is executed. This means that the interface was initialized.
I could not find anything in the JLS to indicate that this should happen. Don't get me wrong, I understand that this should happen in case the implementing class doesn't provide an implementation for the method, but what if it does? Is this condition missing from the Java Language Specification, did I miss something, or am I interpreting it wrongly?

This is a very interesting issue!
It seems like JLS section 12.4.1 ought to cover this definitively. However, the behavior of Oracle JDK and OpenJDK (javac and HotSpot) differs from what's specified here. In particular, the Example 12.4.1-3 from this section covers interface initialization. The example as follows:
interface I {
int i = 1, ii = Test.out("ii", 2);
}
interface J extends I {
int j = Test.out("j", 3), jj = Test.out("jj", 4);
}
interface K extends J {
int k = Test.out("k", 5);
}
class Test {
public static void main(String[] args) {
System.out.println(J.i);
System.out.println(K.j);
}
static int out(String s, int i) {
System.out.println(s + "=" + i);
return i;
}
}
Its expected output is:
1
j=3
jj=4
3
and indeed I get the expected output. However, if a default method is added to interface I,
interface I {
int i = 1, ii = Test.out("ii", 2);
default void method() { } // causes initialization!
}
the output changes to:
1
ii=2
j=3
jj=4
3
which clearly indicates that interface I is being initialized where it wasn't before! The mere presence of the default method is enough to trigger the initialization. The default method doesn't have to be called or overridden or even mentioned, nor does the presence of an abstract method trigger initialization.
My speculation is that the HotSpot implementation wanted to avoid adding class/interface initialization checking into the critical path of the invokevirtual call. Prior to Java 8 and default methods, invokevirtual could never end up executing code in an interface, so this didn't arise. One might think this is part of the class/interface preparation stage (JLS 12.3.2) which initializes things like method tables. But perhaps this went too far and accidentally did full initialization instead.
I've raised this question on the OpenJDK compiler-dev mailing list. There's been a reply from Alex Buckley (editor of the JLS) in which he raises more questions directed at the JVM and lambda implementation teams. He also notes that there's a bug in the spec here where it says "T is a class and a static method declared by T is invoked" should also apply if T is an interface. So, it might be that there are both specification and HotSpot bugs here.
Disclosure: I work for Oracle on OpenJDK. If people think this gives me an unfair advantage at getting the bounty attached to this question, I'm willing to be flexible about it.

The interface is not initialized because the constant field InterfaceType.init , which is being initialized by non constant value (method call), is not used anywhere.
It is known at compile time that constant field of interface is not used anywhere, and the interface is not containing any default method (In java-8) so there is no need to initialize or load the interface.
Interface will be initialized in following cases,
constant field is used in your code.
Interface contains a default method (Java 8)
In case of Default Methods, You are implementing InterfaceType. So, If InterfaceType will contain any default methods, It will be INHERITED (used) in implementing class. And Initialization will be into the picture.
But, If you are accessing constant field of interface (which is initialized in normal way), The interface initialization is not required.
Consider following code.
public class Example {
public static void main(String[] args) throws Exception {
InterfaceType foo = new InterfaceTypeImpl();
System.out.println(InterfaceType.init);
foo.method();
}
}
class InterfaceTypeImpl implements InterfaceType {
#Override
public void method() {
System.out.println("implemented method");
}
}
class ClassInitializer {
static {
System.out.println("static initializer");
}
}
interface InterfaceType {
public static final ClassInitializer init = new ClassInitializer();
public void method();
}
In above case, Interface will be initialized and loaded because you are using the field InterfaceType.init.
I am not giving the default method example as you already given that in your question.
Java language specification and example is given in JLS 12.4.1 (Example does not contain default methods.)
I can not find JLS for Default methods, there may be two possibilities
Java people forgot to consider the case of default method. (Specification Doc bug.)
They just refer the default methods as non-constant member of
interface. (But mentioned no where, again Specification Doc bug.)

The instanceKlass.cpp file from the OpenJDK contains the initialization method InstanceKlass::initialize_impl that corresponds to the Detailed Initialization Procedure in the JLS, which is analogously found in the Initialization section in the JVM Spec.
It contains a new step that is not mentioned in the JLS and not in the JVM book that is referred to in the code:
// refer to the JVM book page 47 for description of steps
...
if (this_oop->has_default_methods()) {
// Step 7.5: initialize any interfaces which have default methods
for (int i = 0; i < this_oop->local_interfaces()->length(); ++i) {
Klass* iface = this_oop->local_interfaces()->at(i);
InstanceKlass* ik = InstanceKlass::cast(iface);
if (ik->has_default_methods() && ik->should_be_initialized()) {
ik->initialize(THREAD);
....
}
}
}
So this initialization has been implemented explicitly as a new Step 7.5. This indicates that this implementation followed some specification, but it seems that the written specification on the website has not been updated accordingly.
EDIT: As a reference, the commit (from October 2012!) where the respective step has been included in the implementation: http://hg.openjdk.java.net/jdk8/build/hotspot/rev/4735d2c84362
EDIT2: Coincidentally, I found this Document about default methods in hotspot which contains an interesting side note at the end:
3.7 Miscellaneous
Because interfaces now have bytecode in them, we must initialize them at the
time that an implementing class is initialized.

I'll try to make a case that an interface initialization should not cause any side-channel side effects that the subtypes depend on, therefore, whether this is a bug or not, or whichever way the Java fixes it, it should not matter to the application in which order interfaces are initialized.
In the case of a class, it is well accepted that it can cause side effects that subclasses depend on. For example
class Foo{
static{
Bank.deposit($1000);
...
Any subclass of Foo would expect that they'll see $1000 in the bank, anywhere in the subclass code. Therefore the superclass is initialized prior to the subclass.
Shouldn't we do the same thing for superintefaces as well? Unfortunately, the order of superinterfaces are not supposed to be significant, therefore there is no well defined order in which to initialize them.
So we better not establish this kind of side effects in interface initializations. After all, interface is not meant for these features (static fields/methods) we pile on for convenience.
Therefore if we follow that principle, it'll be no concern to us in which order interfaces are initialized.

Related

Should I initialize my JComponents when declared or initialize them inside the constructor? [duplicate]

Is there any advantage for either approach?
Example 1:
class A {
B b = new B();
}
Example 2:
class A {
B b;
A() {
b = new B();
}
}
There is no difference - the instance variable initialization is actually put in the constructor(s) by the compiler.
The first variant is more readable.
You can't have exception handling with the first variant.
There is additionally the initialization block, which is as well put in the constructor(s) by the compiler:
{
a = new A();
}
Check Sun's explanation and advice
From this tutorial:
Field declarations, however, are not part of any method, so they cannot be executed as statements are. Instead, the Java compiler generates instance-field initialization code automatically and puts it in the constructor or constructors for the class. The initialization code is inserted into a constructor in the order it appears in the source code, which means that a field initializer can use the initial values of fields declared before it.
Additionally, you might want to lazily initialize your field. In cases when initializing a field is an expensive operation, you may initialize it as soon as it is needed:
ExpensiveObject o;
public ExpensiveObject getExpensiveObject() {
if (o == null) {
o = new ExpensiveObject();
}
return o;
}
And ultimately (as pointed out by Bill), for the sake of dependency management, it is better to avoid using the new operator anywhere within your class. Instead, using Dependency Injection is preferable - i.e. letting someone else (another class/framework) instantiate and inject the dependencies in your class.
Another option would be to use Dependency Injection.
class A{
B b;
A(B b) {
this.b = b;
}
}
This removes the responsibility of creating the B object from the constructor of A. This will make your code more testable and easier to maintain in the long run. The idea is to reduce the coupling between the two classes A and B. A benefit that this gives you is that you can now pass any object that extends B (or implements B if it is an interface) to A's constructor and it will work. One disadvantage is that you give up encapsulation of the B object, so it is exposed to the caller of the A constructor. You'll have to consider if the benefits are worth this trade-off, but in many cases they are.
I got burned in an interesting way today:
class MyClass extends FooClass {
String a = null;
public MyClass() {
super(); // Superclass calls init();
}
#Override
protected void init() {
super.init();
if (something)
a = getStringYadaYada();
}
}
See the mistake? It turns out that the a = null initializer gets called after the superclass constructor is called. Since the superclass constructor calls init(), the initialization of a is followed by the a = null initialization.
my personal "rule" (hardly ever broken) is to:
declare all variables at the start of
a block
make all variables final unless they
cannot be
declare one variable per line
never initialize a variable where
declared
only initialize something in a
constructor when it needs data from
the constructor to do the
initialization
So I would have code like:
public class X
{
public static final int USED_AS_A_CASE_LABEL = 1; // only exception - the compiler makes me
private static final int A;
private final int b;
private int c;
static
{
A = 42;
}
{
b = 7;
}
public X(final int val)
{
c = val;
}
public void foo(final boolean f)
{
final int d;
final int e;
d = 7;
// I will eat my own eyes before using ?: - personal taste.
if(f)
{
e = 1;
}
else
{
e = 2;
}
}
}
This way I am always 100% certain where to look for variables declarations (at the start of a block), and their assignments (as soon as it makes sense after the declaration). This winds up potentially being more efficient as well since you never initialize a variable with a value that is not used (for example declare and init vars and then throw an exception before half of those vars needed to have a value). You also do not wind up doing pointless initialization (like int i = 0; and then later on, before "i" is used, do i = 5;.
I value consistency very much, so following this "rule" is something I do all the time, and it makes it much easier to work with the code since you don't have to hunt around to find things.
Your mileage may vary.
Example 2 is less flexible. If you add another constructor, you need to remember to instantiate the field in that constructor as well. Just instantiate the field directly, or introduce lazy loading somewhere in a getter.
If instantiation requires more than just a simple new, use an initializer block. This will be run regardless of the constructor used. E.g.
public class A {
private Properties properties;
{
try {
properties = new Properties();
properties.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("file.properties"));
} catch (IOException e) {
throw new ConfigurationException("Failed to load properties file.", e); // It's a subclass of RuntimeException.
}
}
// ...
}
Using either dependency injection or lazy initialization is always preferable, as already explained thoroughly in other answers.
When you don't want or can't use those patterns, and for primitive data types, there are three compelling reasons that I can think of why it's preferable to initialize the class attributes outside the constructor:
avoided repetition = if you have more than one constructor, or when you will need to add more, you won't have to repeat the initialization over and over in all the constructors bodies;
improved readability = you can easily tell with a glance which variables will have to be initialized from outside the class;
reduced lines of code = for every initialization done at the declaration there will be a line less in the constructor.
I take it is almost just a matter of taste, as long as initialization is simple and doesn't need any logic.
The constructor approach is a bit more fragile if you don't use an initializer block, because if you later on add a second constructor and forget to initialize b there, you'll get a null b only when using that last constructor.
See http://java.sun.com/docs/books/tutorial/java/javaOO/initial.html for more details about initialization in Java (and for explanations on initalizer blocks and other not well known initialization features).
I've not seen the following in the replies:
A possible advantage of having the initialisation at the time of declaration might be with nowadays IDE's where you can very easily jump to the declaration of a variable (mostly
Ctrl-<hover_over_the_variable>-<left_mouse_click>) from anywhere in your code. You then immediately see the value of that variable. Otherwise, you have to "search" for the place where the initialisation is done (mostly: constructor).
This advantage is of course secondary to all other logical reasonings, but for some people that "feature" might be more important.
Both of the methods are acceptable. Note that in the latter case b=new B() may not get initialized if there is another constructor present. Think of initializer code outside constructor as a common constructor and the code is executed.
I think Example 2 is preferable. I think the best practice is to declare outside the constructor and initialize in the constructor.
The second is an example of lazy initialization. First one is more simple initialization, they are essentially same.
There is one more subtle reason to initialize outside the constructor that no one has mentioned before (very specific I must say). If you are using UML tools to generate class diagrams from the code (reverse engineering), most of the tools I believe will note the initialization of Example 1 and will transfer it to a diagram (if you prefer it to show the initial values, like I do). They will not take these initial values from Example 2. Again, this is a very specific reason - if you are working with UML tools, but once I learned that, I am trying to take all my default values outside of constructor unless, as was mentioned before, there is an issue of possible exception throwing or complicated logic.
The second option is preferable as allows to use different logic in ctors for class instantiation and use ctors chaining. E.g.
class A {
int b;
// secondary ctor
A(String b) {
this(Integer.valueOf(b));
}
// primary ctor
A(int b) {
this.b = b;
}
}
So the second options is more flexible.
It's quite different actually:
The declaration happens before construction. So say if one has initialized the variable (b in this case) at both the places, the constructor's initialization will replace the one done at the class level.
So declare variables at the class level, initialize them in the constructor.
class MyClass extends FooClass {
String a = null;
public MyClass() {
super(); // Superclass calls init();
}
#Override
protected void init() {
super.init();
if (something)
a = getStringYadaYada();
}
}
Regarding the above,
String a = null;
null init could be avoided since anyway it's the default.
However, if you were to need another default value,
then, because of the uncontrolled initialization order,
I would fix as follow:
class MyClass extends FooClass
{
String a;
{
if( a==null ) a="my custom default value";
}
...

Does java forward referencing act differently in different situations?

Please take a look at this snippet:
public class A {
void method() {
System.out.print(B.j);//This is legal!
class C {
void method () {
System.out.print(j);//This is illegal!
}
}
final int j = 10;
class D {
void method() {
System.out.print(j);//This is legal!
}
}
}
}
class B {
static int j = 10;
}
We can access the 'B.j' in a place before it's definition whilst this is illegal in the case of accessing 'final int j' in class C.
Does java compiler looks at local classes as simple variables/objects? Specially, what's the rationale behind this behavior? I mean forward checking is working for the B.j but it doesn't work for the 'j' inside the class C.
I believe this is simple scoping. If you replace your inner classes with simple System.out.println() calls,
public class A {
void method() {
System.out.print(j);//This is illegal!
final int j = 10;
System.out.print(j);//This is legal!
}
}
you'll find you get the same message. The scope of local variables starts where they are declared and continues through the end of the block they're declared in.
To answer your question about the reference to B: Consider
public class A {
void method() {
System.out.print(k);//This is legal!
}
int k=17;
}
Java is not a single-pass compilation. Classes, and their exposed fields and methods, can be forward referenced. A deliberate decision was made that local variables can not be forward referenced. I'm guessing that this was to let programmers establish restricted scopes without having to use additional levels of {} block statements -- if I introduce a new variable, especially with an initialization, I don't want anyone tampering with it before that.
That's how Java local variables happen to work. This may not be a satisfying answer, but it's the best one we've got.
Setting the possibility that your code does not compile aside...
When class A is loaded by the classloader into memory, so is class B, because they're in the same file. So B.j is already allocated on the heap when method is called at runtime.
On the other hand, when you declare variables in a method, those variables are stored on the stack when the method is invoked, in the order that you write them, so here order matters.

Should I instantiate instance variables on declaration or in the constructor?

Is there any advantage for either approach?
Example 1:
class A {
B b = new B();
}
Example 2:
class A {
B b;
A() {
b = new B();
}
}
There is no difference - the instance variable initialization is actually put in the constructor(s) by the compiler.
The first variant is more readable.
You can't have exception handling with the first variant.
There is additionally the initialization block, which is as well put in the constructor(s) by the compiler:
{
a = new A();
}
Check Sun's explanation and advice
From this tutorial:
Field declarations, however, are not part of any method, so they cannot be executed as statements are. Instead, the Java compiler generates instance-field initialization code automatically and puts it in the constructor or constructors for the class. The initialization code is inserted into a constructor in the order it appears in the source code, which means that a field initializer can use the initial values of fields declared before it.
Additionally, you might want to lazily initialize your field. In cases when initializing a field is an expensive operation, you may initialize it as soon as it is needed:
ExpensiveObject o;
public ExpensiveObject getExpensiveObject() {
if (o == null) {
o = new ExpensiveObject();
}
return o;
}
And ultimately (as pointed out by Bill), for the sake of dependency management, it is better to avoid using the new operator anywhere within your class. Instead, using Dependency Injection is preferable - i.e. letting someone else (another class/framework) instantiate and inject the dependencies in your class.
Another option would be to use Dependency Injection.
class A{
B b;
A(B b) {
this.b = b;
}
}
This removes the responsibility of creating the B object from the constructor of A. This will make your code more testable and easier to maintain in the long run. The idea is to reduce the coupling between the two classes A and B. A benefit that this gives you is that you can now pass any object that extends B (or implements B if it is an interface) to A's constructor and it will work. One disadvantage is that you give up encapsulation of the B object, so it is exposed to the caller of the A constructor. You'll have to consider if the benefits are worth this trade-off, but in many cases they are.
I got burned in an interesting way today:
class MyClass extends FooClass {
String a = null;
public MyClass() {
super(); // Superclass calls init();
}
#Override
protected void init() {
super.init();
if (something)
a = getStringYadaYada();
}
}
See the mistake? It turns out that the a = null initializer gets called after the superclass constructor is called. Since the superclass constructor calls init(), the initialization of a is followed by the a = null initialization.
my personal "rule" (hardly ever broken) is to:
declare all variables at the start of
a block
make all variables final unless they
cannot be
declare one variable per line
never initialize a variable where
declared
only initialize something in a
constructor when it needs data from
the constructor to do the
initialization
So I would have code like:
public class X
{
public static final int USED_AS_A_CASE_LABEL = 1; // only exception - the compiler makes me
private static final int A;
private final int b;
private int c;
static
{
A = 42;
}
{
b = 7;
}
public X(final int val)
{
c = val;
}
public void foo(final boolean f)
{
final int d;
final int e;
d = 7;
// I will eat my own eyes before using ?: - personal taste.
if(f)
{
e = 1;
}
else
{
e = 2;
}
}
}
This way I am always 100% certain where to look for variables declarations (at the start of a block), and their assignments (as soon as it makes sense after the declaration). This winds up potentially being more efficient as well since you never initialize a variable with a value that is not used (for example declare and init vars and then throw an exception before half of those vars needed to have a value). You also do not wind up doing pointless initialization (like int i = 0; and then later on, before "i" is used, do i = 5;.
I value consistency very much, so following this "rule" is something I do all the time, and it makes it much easier to work with the code since you don't have to hunt around to find things.
Your mileage may vary.
Example 2 is less flexible. If you add another constructor, you need to remember to instantiate the field in that constructor as well. Just instantiate the field directly, or introduce lazy loading somewhere in a getter.
If instantiation requires more than just a simple new, use an initializer block. This will be run regardless of the constructor used. E.g.
public class A {
private Properties properties;
{
try {
properties = new Properties();
properties.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("file.properties"));
} catch (IOException e) {
throw new ConfigurationException("Failed to load properties file.", e); // It's a subclass of RuntimeException.
}
}
// ...
}
Using either dependency injection or lazy initialization is always preferable, as already explained thoroughly in other answers.
When you don't want or can't use those patterns, and for primitive data types, there are three compelling reasons that I can think of why it's preferable to initialize the class attributes outside the constructor:
avoided repetition = if you have more than one constructor, or when you will need to add more, you won't have to repeat the initialization over and over in all the constructors bodies;
improved readability = you can easily tell with a glance which variables will have to be initialized from outside the class;
reduced lines of code = for every initialization done at the declaration there will be a line less in the constructor.
I take it is almost just a matter of taste, as long as initialization is simple and doesn't need any logic.
The constructor approach is a bit more fragile if you don't use an initializer block, because if you later on add a second constructor and forget to initialize b there, you'll get a null b only when using that last constructor.
See http://java.sun.com/docs/books/tutorial/java/javaOO/initial.html for more details about initialization in Java (and for explanations on initalizer blocks and other not well known initialization features).
I've not seen the following in the replies:
A possible advantage of having the initialisation at the time of declaration might be with nowadays IDE's where you can very easily jump to the declaration of a variable (mostly
Ctrl-<hover_over_the_variable>-<left_mouse_click>) from anywhere in your code. You then immediately see the value of that variable. Otherwise, you have to "search" for the place where the initialisation is done (mostly: constructor).
This advantage is of course secondary to all other logical reasonings, but for some people that "feature" might be more important.
Both of the methods are acceptable. Note that in the latter case b=new B() may not get initialized if there is another constructor present. Think of initializer code outside constructor as a common constructor and the code is executed.
I think Example 2 is preferable. I think the best practice is to declare outside the constructor and initialize in the constructor.
The second is an example of lazy initialization. First one is more simple initialization, they are essentially same.
There is one more subtle reason to initialize outside the constructor that no one has mentioned before (very specific I must say). If you are using UML tools to generate class diagrams from the code (reverse engineering), most of the tools I believe will note the initialization of Example 1 and will transfer it to a diagram (if you prefer it to show the initial values, like I do). They will not take these initial values from Example 2. Again, this is a very specific reason - if you are working with UML tools, but once I learned that, I am trying to take all my default values outside of constructor unless, as was mentioned before, there is an issue of possible exception throwing or complicated logic.
The second option is preferable as allows to use different logic in ctors for class instantiation and use ctors chaining. E.g.
class A {
int b;
// secondary ctor
A(String b) {
this(Integer.valueOf(b));
}
// primary ctor
A(int b) {
this.b = b;
}
}
So the second options is more flexible.
It's quite different actually:
The declaration happens before construction. So say if one has initialized the variable (b in this case) at both the places, the constructor's initialization will replace the one done at the class level.
So declare variables at the class level, initialize them in the constructor.
class MyClass extends FooClass {
String a = null;
public MyClass() {
super(); // Superclass calls init();
}
#Override
protected void init() {
super.init();
if (something)
a = getStringYadaYada();
}
}
Regarding the above,
String a = null;
null init could be avoided since anyway it's the default.
However, if you were to need another default value,
then, because of the uncontrolled initialization order,
I would fix as follow:
class MyClass extends FooClass
{
String a;
{
if( a==null ) a="my custom default value";
}
...

Overriding with subclass as a parameter and generics: where is it in Java Lang Spec?

I've run into Java code similar to the following:
public interface BaseArg {
}
public class DerivedArg implements BaseArg {
}
public abstract class Base <A extends BaseArg> {
A arg;
void doIt() {
printArg(arg);
}
void printArg(A a) {
System.out.println("Base: " + a);
}
}
public class Derived extends Base<DerivedArg> {
void printArg(DerivedArg a) {
System.out.println("Derived: " + a);
}
public static void main(String[] args) {
Derived d = new Derived();
d.arg = new DerivedArg();
d.doIt();
}
}
(feel free to split it into files and run it).
This code ends up invoking the Derived printArg. I realize it's the only logical thing to do. However, if I perform "erasure" on the generic Base manually, replacing all occurrences of A with BaseArg, the overriding breaks down. I now get the Base's version of printIt.
Seems like "erasure" is not total - somehow printArg(A a) is not the same as printArg(BaseArg a). I can't find any basis for this in the language spec...
What am I missing in the language spec? It's not really important, but it bugs me :) .
Please note that the derived method is invoked. The question is why, considering their erased signatures are not override-equivalent.
When compiling class Derived, the compiler actually emits two methods: The method printArg(DerivedArg), and a synthetic method printArg(BaseArg), which overrides the superclass method in terms even a virtual machine ignorant of type parameters can understand, and delegates to printArg(DerivedArg). You can verify this by throwing an exception in printArt(DerivedArg), while calling it on a reference of type Base, and examining the stack trace:
Exception in thread "main" java.lang.RuntimeException
at Derived.printArg(Test.java:28)
at Derived.printArg(Test.java:1) << synthetic
at Base.doIt(Test.java:14)
at Test.main(Test.java:39)
As for finding this in the Java Language Specification, I first missed it as well, as it is not, as one might expect, specified where overriding or the subsignature relation is discussed, but in "Members and Constructors of Parameterized Types" (ยง4.5.2), which reveals that formal type parameters of the superclass are syntactically replaced by the actual type parameter in the subclass prior to checking for override equivalence.
That is, override equivalence is not affected by erasure, contrary to popular assumption.
If you do "manual" type erasure, you define the arg instance in BaseArg as type "BaseArg", not type "DerivedArg", so that's resolved to Base's "doIt(BaseArg)" method rather than Derived's "doIt(DerivedArg)" method. If you then alter Derived's method signature to
void printArg( BaseArg a )
from
void printArg(DerivedArg a)
it will print "Derived: arg" as expected.
I believe the behaviour that you encountered is due to the overloading method resolution.
See Java Lang Spec on overloading: link text
And also this wonderful resource on Java Generic regarding the topic.
The printArg in Derived does not override the printArg in Base. In order for it to override, by JLS 8.4.8.1, the overriding method's signature must be a "subsignature" of the overridden method's. And then by JLS 8.4.2, a subsignature must either have the same argument types (which yours doesn't), or its erasure must be the same (which is also not true).
First of all, you can compile the source code in a single file if you get rid of the "public" declarations for all of the classes/interfaces except "Derived".
Second, go ahead and do the type erasure by hand. Here's what I got when I did it:
interface BaseArg {}
class DerivedArg implements BaseArg {}
abstract class Base {
BaseArg arg;
void doIt() {
printArg(arg);
}
void printArg(BaseArg a) {
System.out.println("Base: " + a);
}
}
public class Derived extends Base {
void printArg(BaseArg a) {
System.out.println("Derived: " + a);
}
public static void main(String[] args) {
Derived d = new Derived();
d.arg = new DerivedArg();
d.doIt();
}
}
In the generic version of the code, it may look like methods Derived.printArg and Base.printArg have different signatures. However, if that were the case, then Derived.printArg could never be invoked by doIt. The type-erased version of the code makes it clear that Derived.printArg overrides Base.printArg, so doIt polymorphically calls the right method.
How is printArg in Base defined after your manual erasure ?
void printArg(BaseArg a) {
so, printArg(Derived a) does NOT override it and will not be called.
EDIT:
if you use the Override annotation in Derived, you'll get an error doing the manual erasure.

Use of Initializers vs Constructors in Java

So I've been brushing up on my Java skills as of late and have found a few bits of functionality that I didn't know about previously. Static and Instance Initializers are two such techniques.
My question is when would one use an initializer instead of including the code in a constructor? I've thought of a couple obvious possibilities:
static/instance initializers can be used to set the value of "final" static/instance variables whereas a constructor cannot
static initializers can be used to set the value of any static variables in a class, which should be more efficient than having an "if (someStaticVar == null) // do stuff" block of code at the start of each constructor
Both of these cases assume that the code required to set these variables is more complex than simply "var = value", as otherwise there wouldn't seem to be any reason to use an initializer instead of simply setting the value when declaring the variable.
However, while these aren't trivial gains (especially the ability to set a final variable), it does seem that there are a rather limited number of situations in which an initializer should be used.
One can certainly use an initializer for a lot of what is done in a constructor, but I don't really see the reason to do so. Even if all constructors for a class share a large amount of code, the use of a private initialize() function seems to make more sense to me than using an initializer because it doesn't lock you into having that code run when writing a new constructor.
Am I missing something? Are there a number of other situations in which an initializer should be used? Or is it really just a rather limited tool to be used in very specific situations?
Static initializers are useful as cletus mentioned and I use them in the same manner. If you have a static variable that is to be initialized when the class is loaded, then a static initializer is the way to go, especially as it allows you to do a complex initialization and still have the static variable be final. This is a big win.
I find "if (someStaticVar == null) // do stuff" to be messy and error prone. If it is initialized statically and declared final, then you avoid the possibility of it being null.
However, I'm confused when you say:
static/instance initializers can be used to set the value of "final"
static/instance variables whereas a constructor cannot
I assume you are saying both:
static initializers can be used to set the value of "final" static variables whereas a constructor cannot
instance initializers can be used to set the value of "final" instance variables whereas a constructor cannot
and you are correct on the first point, wrong on the second. You can, for example, do this:
class MyClass {
private final int counter;
public MyClass(final int counter) {
this.counter = counter;
}
}
Also, when a lot of code is shared between constructors, one of the best ways to handle this is to chain constructors, providing the default values. This makes is pretty clear what is being done:
class MyClass {
private final int counter;
public MyClass() {
this(0);
}
public MyClass(final int counter) {
this.counter = counter;
}
}
Anonymous inner classes can't have a constructor (as they're anonymous), so they're a pretty natural fit for instance initializers.
I most often use static initializer blocks for setting up final static data, especially collections. For example:
public class Deck {
private final static List<String> SUITS;
static {
List<String> list = new ArrayList<String>();
list.add("Clubs");
list.add("Spades");
list.add("Hearts");
list.add("Diamonds");
SUITS = Collections.unmodifiableList(list);
}
...
}
Now this example can be done with a single line of code:
private final static List<String> SUITS =
Collections.unmodifiableList(
Arrays.asList("Clubs", "Spades", "Hearts", "Diamonds")
);
but the static version can be far neater, particularly when the items are non-trivial to initialize.
A naive implementation may also not create an unmodifiable list, which is a potential mistake. The above creates an immutable data structure that you can happily return from public methods and so on.
Just to add to some already excellent points here. The static initializer is thread safe. It is executed when the class is loaded, and thus makes for simpler static data initialization than using a constructor, in which you would need a synchronized block to check if the static data is initialized and then actually initialize it.
public class MyClass {
static private Properties propTable;
static
{
try
{
propTable.load(new FileInputStream("/data/user.prop"));
}
catch (Exception e)
{
propTable.put("user", System.getProperty("user"));
propTable.put("password", System.getProperty("password"));
}
}
versus
public class MyClass
{
public MyClass()
{
synchronized (MyClass.class)
{
if (propTable == null)
{
try
{
propTable.load(new FileInputStream("/data/user.prop"));
}
catch (Exception e)
{
propTable.put("user", System.getProperty("user"));
propTable.put("password", System.getProperty("password"));
}
}
}
}
Don't forget, you now have to synchronize at the class, not instance level. This incurs a cost for every instance constructed instead of a one time cost when the class is loaded. Plus, it's ugly ;-)
I read a whole article looking for an answer to the init order of initializers vs. their constructors. I didn't find it, so I wrote some code to check my understanding. I thought I would add this little demonstration as a comment. To test your understanding, see if you can predict the answer before reading it at the bottom.
/**
* Demonstrate order of initialization in Java.
* #author Daniel S. Wilkerson
*/
public class CtorOrder {
public static void main(String[] args) {
B a = new B();
}
}
class A {
A() {
System.out.println("A ctor");
}
}
class B extends A {
int x = initX();
int initX() {
System.out.println("B initX");
return 1;
}
B() {
super();
System.out.println("B ctor");
}
}
Output:
java CtorOrder
A ctor
B initX
B ctor
A static initializer is the equivalent of a constructor in the static context. You will certainly see that more often than an instance initializer. Sometimes you need to run code to set up the static environment.
In general, an instance initalizer is best for anonymous inner classes. Take a look at JMock's cookbook to see an innovative way to use it to make code more readable.
Sometimes, if you have some logic which is complicated to chain across constructors (say you are subclassing and you can't call this() because you need to call super()), you could avoid duplication by doing the common stuff in the instance initalizer. Instance initalizers are so rare, though, that they are a surprising syntax to many, so I avoid them and would rather make my class concrete and not anonymous if I need the constructor behavior.
JMock is an exception, because that is how the framework is intended to be used.
There is one important aspect that you have to consider in your choice:
Initializer blocks are members of the class/object, while constructors are not.
This is important when considering extension/subclassing:
Initializers are inherited by subclasses. (Though, can be shadowed)
This means it is basically guaranteed that subclasses are initialized as intended by the parent class.
Constructors are not inherited, though. (They only call super() [i.e. no parameters] implicitly or you have to make a specific super(...) call manually.)
This means it is possible that a implicit or exclicit super(...) call might not initialize the subclass as intended by the parent class.
Consider this example of an initializer block:
class ParentWithInitializer {
protected String aFieldToInitialize;
{
aFieldToInitialize = "init";
System.out.println("initializing in initializer block of: "
+ this.getClass().getSimpleName());
}
}
class ChildOfParentWithInitializer extends ParentWithInitializer{
public static void main(String... args){
System.out.println(new ChildOfParentWithInitializer().aFieldToInitialize);
}
}
output:
initializing in initializer block of: ChildOfParentWithInitializer
init
-> No matter what constructors the subclass implements, the field will be initialized.
Now consider this example with constructors:
class ParentWithConstructor {
protected String aFieldToInitialize;
// different constructors initialize the value differently:
ParentWithConstructor(){
//init a null object
aFieldToInitialize = null;
System.out.println("Constructor of "
+ this.getClass().getSimpleName() + " inits to null");
}
ParentWithConstructor(String... params) {
//init all fields to intended values
aFieldToInitialize = "intended init Value";
System.out.println("initializing in parameterized constructor of:"
+ this.getClass().getSimpleName());
}
}
class ChildOfParentWithConstructor extends ParentWithConstructor{
public static void main (String... args){
System.out.println(new ChildOfParentWithConstructor().aFieldToInitialize);
}
}
output:
Constructor of ChildOfParentWithConstructor inits to null
null
-> This will initialize the field to null by default, even though it might not be the result you wanted.
I would also like to add one point along with all the above fabulous answers . When we load a driver in JDBC using Class.forName("") the the Class loading happens and the static initializer of the Driver class gets fired and the code inside it registers Driver to Driver Manager. This is one of the significant use of static code block.
As you mentioned, it's not useful in a lot of cases and as with any less-used syntax, you probably want to avoid it just to stop the next person looking at your code from spending the 30 seconds to pull it out of the vaults.
On the other hand, it is the only way to do a few things (I think you pretty much covered those).
Static variables themselves should be somewhat avoided anyway--not always, but if you use a lot of them, or you use a lot in one class, you might find different approaches, your future self will thank you.
Note that one big issue with static initializers that perform some side effects, is that they cannot be mocked in unit tests.
I've seen libraries do that, and it's a big pain.
So it's best to keep those static initializers pure only.

Categories

Resources