I just discovered something quite weird. If a final variable is called from the implicit super constructor using an overriden method, the element will never not be initialiazed upon call :
public static abstract class A {
public A()
{
doSomething();
}
public abstract void doSomething();
}
public static class B extends A {
private final Object s = new Object();
public B()
{
}
public void doSomething() {
System.out.println(s);
}
}
public static void main( String[] args )
{
new B();// prints 'null'
}
If the method is not overriden, the final variable will be correctly instanciated :
public static class B {
private final Object s = new Object();
public B()
{
doSomething();
}
public void doSomething() {
System.out.println(s);
}
}
public static void main( String[] args )
{
new B(); // prints the object correctly
}
Finally, even stranger for me (i think this is relative to the String#intern mechanism)
public static abstract class A {
public A()
{
doSomething();
}
public abstract void doSomething();
}
public static class B extends A {
private final String s = "Hello";
public B()
{
}
public void doSomething() {
System.out.println(s);
}
}
public static void main( String[] args )
{
new B(); // will print "Hello"
}
My question is what can i do in the first case to fix this, should i use a getter that ensures non-null value ?
I sort of understand why the first case occurs (the constructor implicitely calls the 'super' constructor before initialization of any instance vars), but, if i am correct, in this case why is the 3rd case prints correctly 'Hello' ?
It's important to understand that constructors of base classes are executed before constructors of subclasses. This means than fields of subclasses may not have been initialized during construction of base classes. (They will however be initialized during construction of the subclasses.)
My question is what can i do in the first case to fix this, should i use a getter that ensures non-null value ?
The problem you've discovered is one of the reasons to never ever call overridable methods from within the constructor.
A getter is probably just as bad, since the getter would also be overridable.
Instead of having
Object s = new Object();
...
public void doSomething() {
System.out.println(s);
}
in B, you can pass the variable to be used in the construction of A as an argument to As constructor:
public B() {
super(new Object());
}
This passes the data relevant for constructing the B object, so that the constructor of B is "self-contained". This is quite messy though, and I would advice you to reconsider the structure of your classes.
Regarding the third case:
private final String s = "Hello";
Since "Hello" is a compile time constant expression, and since s is final, the Java compiler is free to inline the use of s, i.e. replace s with "Hello" at it's discretion.
Related
I have two Java classes, one of which inherits from other. They are somewhat like the following:
A.java:
public class A {
public String invocations[] = {"foo"};
public A() {
// do stuff
}
}
B.java:
public class B extends A {
public String invocations = {"bar", "baz"};
public B() {
super();
}
}
In this example, assuming I create an instance of B and get its invocations property, it returns {"foo"} instead of the expected {"bar", "baz"}. Why is this, and how can I get the {"bar", "baz"}?
You have one variable hiding another one. You can refer to a variable in a super class by using a cast to the type explicitly. (I am assuming you fix the syntax errors)
public class Main {
static class A {
public String[] invocations = {"foo"};
}
static class B extends A {
public String[] invocations = {"bar", "baz"};
}
public static void main(String... args) {
B b = new B();
System.out.println("((A)b).invocations=" + Arrays.toString(((A) b).invocations));
System.out.println("b.invocations=" + Arrays.toString(b.invocations));
}
}
prints
((A)b).invocations=[foo]
b.invocations=[bar, baz]
I wrote this simple class in java just for testing some of its features.
public class class1 {
public static Integer value=0;
public class1() {
da();
}
public int da() {
class1.value=class1.value+1;
return 5;
}
public static void main(String[] args) {
class1 h = new class1();
class1 h2 = new class1();
System.out.println(class1.value);
}
}
The output is:
2
But in this code:
public class class1 {
public static Integer value=0;
public void class1() {
da();
}
public int da() {
class1.value=class1.value+1;
return 5;
}
public static void main(String[] args) {
class1 h = new class1();
class1 h2 = new class1();
System.out.println(class1.value);
}
}
The output of this code is:
0
So why doesn't, when I use void in the constructor method declaration, the static field of the class doesn't change any more?
In Java, the constructor is not a method. It only has the name of the class and a specific visibility. If it declares that returns something, then it is not a constructor, not even if it declares that returns a void. Note the difference here:
public class SomeClass {
public SomeClass() {
//constructor
}
public void SomeClass() {
//a method, NOT a constructor
}
}
Also, if a class doesn't define a constructor, then the compiler will automatically add a default constructor for you.
public void class1() is not a constructor, it is a void method whose name happens to match the class name. It is never called. Instead java creates a default constructor (since you have not created one), which does nothing.
Using void in the constructor by definition leads it to not longer be the constructor.
The constructor specifically has no return type. While void doesn't return a value in the strictest sense of the word, it is still considered a return type.
In the second example (where you use the void), you would have to do h.class1() for the method to get called because it is no longer the constructor. Or you could just remove the void.
This is arguably a design flaw in Java.
class MyClass {
// this is a constructor
MyClass() {...}
// this is an instance method
void MyClass() {...}
}
Perfectly legal. Probably shouldn't be, but is.
In your example, class1() is never getting called, because it's not a constructor. Instead, the default constructor is getting called.
Suggestion: familiarize yourself with Java naming conventions. Class names should start with uppercase.
The reason the constructor doesn't return a value is because it's not called directly by your code, it's called by the memory allocation and object initialization code in the run time.
Here is an article explaining this in greater detail:
https://www.quora.com/Why-is-the-return-type-of-constructor-not-void-while-the-return-type-of-a-function-can-be-void
I wrote down this mini-program:
A class:
public class A
{
public A()
{
System.out.println(getS());
}
public String getS() { return s;}
}
B class:
public class B extends A
{
private String s = "hello2";
public String getS() { return s;}
}
main:
public static void main(String[] args)
{
B b = new B();
}
and it printed:
null
Why is that?
I know that the String that printed is B's string, but why it didn't initialized before?
According to this answer - the variable initialized before the constructor..
EDIT -
I edited the code so the unrelated code won't confuse
Here is what's going on: when you construct B, the first thing its constructor needs to do is constructing A. This is done before B's own field s is initialized.
A constructs its own s, and then calls getS. However, it does not get its own getS, because B provides an override for it. Recall that B.s has not been initialized yet. That is why you see null printed.
Follow-up reading: What's wrong with overridable method calls in constructors?
What is happening:
You create a B instance, this will call the super() so the constructor of A.
Here it will do the print using the getter getS(). This will use the getter of B since this is the type of this but in this getter, the String is not yet instanciate since it is still doing the super class construction, so it return null.
Note that the String s in A is hidden by the one in B
The order during an instance is :
the static (from the super then the class)
the super class declaration (statement then constructor)
the block statement
the constructor
As Seen with :
public class A{
static{System.out.println("sA");}
{System.out.println("A1");}
public Main() {
System.out.println("new A");
}
{System.out.println("A2");}
public static void main(String[] args) {
new A();
}
}
class B extends Main {
static{System.out.println("sB");}
{ System.out.println("B1"); }
public B() {
System.out.println("new B");
}
{ System.out.println("B2"); }
}
Output :
sA
sB
A1
A2
new A
B1
B2
new B
it prints null because you have polymorphism in java. You Overrided method getS(). So when you call it from A, you try to call getS() from class B. But you didn't create instance of class B yet, because you need to finish class A first. So String in class B haven't been initialized yet, because of it you get null.
Okay, so I'm not sure if this question already exists because I don't know how to format it, but here's the problem: can a same method produce different result depending on a constructor? (I apologize if I'm repeating the question or if it's a stupid question.)
For example, let's say that I have an interface MyInterface with function public void foo();. Let's say we have class:
public class MyClass implements MyInterface {
public MyClass() {
// I want foo() to print "Empty constructor" with sysout.
}
public MyClass(int x) {
// I want foo() to print "Constructor with int" with sysout.
}
}
So now, if create two references MyClass mc1 = new MyClass(); and MyClass mc2 = new MyClass(5); and then call mc1.foo(); and mc2.foo();, the result should be:
Empty constructor.
Constructor with int.
I tried with new MyInterface { #Override public void foo() { ... } } inside constructors but doesn't seem to work.
Yes. Store the variable and check it in the foo method.
public class MyClass implements MyInterface {
private int x;
public MyClass() {
// I want foo() to print "Empty constructor" with sysout.
}
public MyClass(int x) {
// I want foo() to print "Constructor with int" with sysout.
this.x = x;
}
public void foo(){
if(x > 0)
System.out.println("Constructor with int");
else
System.out.println("Empty constructor");
}
}
To answer the question: Not to my knowledge. Or at least not directly, you could start to read byte code and change it during run time, make it adapt-- so again, the answer is no.
Now the weird parts are the override and depending on constructor. It is not in the scope of overriding.
A method doing different things depending on the state of the Class is not too odd. However, making the method unique of how the class was instantiated I've never heard of. That being said, here is a fairly ugly solution to it.
public class Test
{
private final boolean intConstructorUsed;
public Test () {
intConstructorUsed = false;
}
public Test (int x) {
intConstructorUsed = true;
}
public void foo () {
if (intConstructorUsed == true) {
// do this
} else {
// do that
}
}
}
The foo method isn't that weird. The weird part is that you basically have to different implementations of foo depending on which constructor, you are sure you do not want an abstract class behind, with all shared methods except for one abstract void foo () that you override? Sure the classes will almost look identical, however they are not, as they do not share their foo ().
Yes, it's what's multiple constructors are designed to allow for - variation via object creation.
public class MyClass implements MyInterface {
private final String message;
public MyClass() {
message = "Empty constructor";
}
public MyClass(int x) {
message = "Constructor with int";
}
#Override
public void foo() {
System.out.println(message);
}
}
It's even threadsafe.
The thing to note here is that the implementation of the method is exactly the same, the variation is in the constructor. And it's the constructor which is called differently depending on what the caller wants to happen.
need some help on this, If interface cannot have a constructor, what happens here?
interface A{
String toString();
}
public class B{
public static void main(String[] args) {
System.out.println(new A() {
public String toString() {
return "what happens here!!";
}
});
}
}
An instance of an anonymous class implementing A is created.
This has very little to do with constructors, except that the default no-arg constructor will be called, and the toString() method is already defined in the Object class, so the interface is superfluous.
public static void main(String[] args) {
System.out.println(new A() {
public String toString() { return "what happens here!!"; }
});
}
can be more explicitly rewritten as follows:
public static void main(String[] args) {
class ImplA() extends Object implements A {
public ImplA() { super(); }
public String toString() { return "what happens here!!"; }
}
System.out.println(new ImplA());
}
From the above you can understand the following:
the local class ImplA is a subclass of Object and also implements A;
Object has a nullary constructor;
ImplA defines a nullary constructor, which delegates to Object's nullary constructor;
the constructor thus declared is called when writing new ImplA();
Your version of code just employs Java's syntactic sugar which lets you combine local class declaration with class instantiation into a single expression.