This question already has answers here:
How JVM loads parent classes in Java
(3 answers)
Closed 6 years ago.
In the following Java code, the Insect class is inherited by the Beetle class.
class Insect {
private int i = 9;
protected int j;
Insect() {
System.out.println("i = " + i + ", j = " + j);
j = 39;
}
private static int x1
= printInit("static Insect.x1 initialized");
static int printInit(String s) {
System.out.println(s);
return 47;
}
}
public class Beetle extends Insect {
private int k = printInit("Beetle.k initialized");
public Beetle() {
System.out.println("k = " + k);
System.out.println("j = " + j);
}
private static int x2
= printInit("static Beetle.x2 initialized");
public static void main(String[] args) {
System.out.println("Beetle constructor");
Beetle b = new Beetle();
}
}
The output is somehow comfusing.
static Insect.x1 initialized
static Beetle.x2 initialized
Beetle constructor
i = 9, j = 0
Beetle.k initialized
k = 47 j = 39
What is the order of initialization in this particular example?
Why is x2 initialized immediatly after x1? And why is the first line of the main method (System.out.println("Beetle constructor");), executed after x1 and x2 intializaton. So comfusing.
I know that the derived class constructor automatically calls the base class constructor (unless it has parameters and you'd use the super keyword). I know that variables are initialized before the constructor, and that static variables are initialized before other variables.
x1 and x2 are static. This means that they are initialized when the class is loaded. Since the main method is in Beetle, the class has to be loaded before invoking main. This is why x1 and x2 initialization is the first thing you see. Not sure about why the order of those two is as it is.
Now you are calling main and System.out.println("Beetle constructor"); is executed. Then it calls Beetle() which implicitly calls super() (aka Insect()) first. This prints i = 9, j = 0 because i is 9 and j has not been initialized at that point, which means it has the default int value 0.
Now j is set to 39 and the flow continues in Beetle(). This now initializes the fields of Beetle, in your case k. So when it comes to the explicit code in Beetle(), k is initialized to 47 and j to 39 by the super constructor.
This can be explained as follows -
Since static members are non-instance members i.e only one copy of the member is shared across all the instances of the class, these members are initialized first.
In this case, x1 is initialized first since its a static member present in the base class of the class where the main method is present.
Hence, 1st x1 is initialized.
Static member x2 in the subclass follows because of the same reason and also because there are no other static members present in Insect class.
Beetle constructor line is printed from the main method.
The constructors of the super class and sub class are called one after the other for obvious reasons
JVM(Class loader) loads Beetle class, when you invoke its main static method. After class loading, initialization of Beetle class takes place which means initializing all the static members of the class.
The base class is always initialized implicitly, thus you see the x1 initialized before x2.
You see the "Beetle constructor" printed after x1, and x2, because when you reference a static method of a class(as you are doing by calling main), the JVM order of execution jumps to initializing the class static members, before continuing with the execution of the main() method.
As an experiment, try removing the main method to another class,
public class Beetle1 {
public static void main(String[] args) {
System.out.println("Beetle1 constructor");
}
}
Now as the Beetle constructor is not referenced, the class loader does not load it, and you will see Beetle1 constructor printed.
Related
I'm reading the source code of ArrayList and this class has an inner class with the name SubList. I'm looking in a method of the inner class (SubList) and see the following methods:
public E set(int index, E e) {
rangeCheck(index);
checkForComodification();
E oldValue = ArrayList.this.elementData(offset + index);
ArrayList.this.elementData[offset + index] = e;
return oldValue;
}
What I see that line 3 & 4 uses this keyword in order to call/use ArrayList (outer class) method/attribute.
I want to understand is it must to use OuterClass.this or elementData() will be enough? I run an example long ago (more than a year) and I was able to call an outer class method from an inner class without using this keyword.
There is a Shadowing problem that can lead to unexpected behavior and runtime errors.
If a declaration of a type (such as a member variable or a parameter name or method name) in a particular scope (such as an inner class or a method definition) has the same name as another declaration in the enclosing scope, then the declaration shadows the declaration of the enclosing scope. You cannot refer to a shadowed declaration by its name alone.
public class ShadowTest {
public int x = 0;
class FirstLevel {
public int x = 1;
void methodInFirstLevel(int x) {
System.out.println("x = " + x);
System.out.println("this.x = " + this.x);
System.out.println("ShadowTest.this.x = " + ShadowTest.this.x);
}
}
public static void main(String... args) {
ShadowTest st = new ShadowTest();
ShadowTest.FirstLevel fl = st.new FirstLevel();
fl.methodInFirstLevel(23);
}
}
Output:
x = 23
this.x = 1
ShadowTest.this.x = 0
As you can see, to get the correct value of higher scope, you need to use only ShadowTest.this.
Thru time your code will mutate and you can miss the same name in the other scope, so you must use only OuterClass.this to access outer class scope, make code clear and bulletproof.
See the Java Tutorial.
I'm wondering what is happening here:
I have abstract superclass
public abstract class Superclass {
public Superclass()
{
doSth();
}
public abstract void doSth();
}
And subclass
public class Subclass extends Superclass{
private int x = 10;
public void doSth()
{
System.out.println("Value x="+this.x);
}
}
When I make
Subclass x= new Subclass();
x.doSth();
I get:
Value x=0
Value x=10
I don't know why first I get x=0 (why not x=10 from the start?) and then x=10?
The constructor of the super-class is executed before the isntance initializer expressions of the sub-class, which is why x still has the default value of 0 in the first call to doSth(). The second call x.doSth() takes places after the Subclass instance is fully initialized, so x contains 10.
More details :
When you call the constrcutor of Subclass, first it calls the constructor of Superclass which calls the constructor of Object. Then the body of the Superclass constructor is executed, so doSth() is executed. Only after the Superclass constructor is done, the instance initialization expressions of Subclass (in your case, the assignment x = 10; are evaluated. Before they are evaluated, x still contains the default value - 0, which is the value you see printed by the first call to doSth().
I have a Doubt
when we initialize our instance variables in Instance initialization block(s) in case of inheritance do they override the value of variable?
For example
class A{
int x;
}
class B extends A{
int x = 10;
}
public class C{
public static void main(String[] args){
A K = new B();
System.out.println(K.x);
}
}
o/p : 0
However when i use initialization blocks
class A{
int x;
{x = 15;}
}
class B extends A{
{x=20;}
}
public class C{
public static void main(String[] args){
A K = new B();
System.out.println(K.x);
}
}
OUTPUT 20
Why its so? why my initialization block(s) are affecting instance variables ? Moreover , i know that blocks are called when we make object but still the variable at output should correspond to variable type i.e A K (K should give value corresponding to class A)
You can override methods only, not variables. This code isn't "overriding" instance variables.
The first example has a different variables named x defined for A and B, making the variable an A means you see the variable defined for A (see the link provided by paulk23). In the second there is only one instance variable x which is visible to the subclass, the instance initializer assigns a value to an existing variable.
In the first example, you have two declarations of x, and in the second you only have one. In the second example, try changing B to:
class B extends A {
int x;
{ x=20; }
}
and you'll see the same behaviour as the first example: B defines a new variable that has an independent value from the one in A.
The code is like this :
class Base {
int x = 10;
public Base() {
this.printMessage();
x = 20;
}
public void printMessage() {
System.out.println("Base.x = " + x);
}
}
class Sub extends Base {
int x = 30;
public Sub() {
this.printMessage();
x = 40;
}
public void printMessage() {
System.out.println("Sub.x = " + x);
}
}
public class DispatchTest {
public static void main(String[] args) {
Base b = new Sub();
System.out.println(b.x);
}
}
The result is :
Sub.x = 0
Sub.x = 30
20
Can anybody please tell me how this code run?
Why doesn't the costructor of class Base run?
Because you created a new Sub object instance. The class Sub has the printMessage() method overriden, which means that the Base.printMethod() is not being executed.
The constructor of the Base class runs, but the this.printMessage() executes the printMessage method from the Sub class.
Immediatelly after the Sub's constructor has been invoked, the Base constructor is being called. It prints Sub.x = 0 because no x (in Sub) has been set so far. After that the value x gets assigned.
After the Base constructor is done, the rest of the Sub constructor is being executed. It prints calls the Sub's printMessage method again, but this time the value x has a value, and it prints Sub.x = 30.
The 20 comes from the System.out.println(b.x);.
You might wonder, why the value xis not assigned during the first printMessage call? Because you have x in your Sub class as well, so the x from the Base class is not visible!
Your SuperClass constructor is always called but "Polymorphic behaviour cannot be seen when accessing overridden member variables".
Base b = new Sub();
System.out.println(b.x);
Now if you access x(which is present in both subclass and superclass) it is actually the type of reference variable which determines the value.
Note: This behaviour is different with overridden methods,in this case it is actually the type of object which determines the method to be called not the type of reference variable.
The constructor
public Sub() {
this.printMessage();
x = 40;
}
is equivalent to
public Sub() {
super();
this.printMessage();
x = 40;
}
So when you create
Base b = new Sub();
Base's constructor gets executed followed by Sub's constructor. See JLS 8.8.7, which states
The first statement of a constructor body may be an explicit
invocation of another constructor of the same class or of the direct
superclass
Base's constructor is calling printMessage() which is overriden by Sub. When it gets called from Base's constructor printMessage() prints x of Sub which is not yet initialized. This is an anti pattern, so Sub.x = 0 gets printed (x is not yet initialized, and hence default value of int which is 0 )
Now once the Base's constructor finishes, Sub's constructor gets called and now the x is initialized to 30 why?
because
class Sub extends Base {
int x = 30;
public Sub() {
this.printMessage();
x = 40;
}
....
essentially means
class Sub extends Base {
int x;
public Sub() {
{
x=30;
}
this.printMessage();
x = 40;
}
....
hence this time printMessage() prints Sub.x = 30
finally 20 is printed because fields are NOT overriden.
When ever we are creating child class object then the following sequence of events will be executed automatically.
Step 1.Identification of instance members from parent to child and initialize them to default value.
after first step
Base instance variable is int x=0;
Sub instance variable is int x=0;
Step 2. Execution of instance variable assignments and instance blocks only in parent class
after second step
Base class instance variable is int x= 10;
Sub class instance variable is int x = 0;
Step 3.Execution of parent class constructor.
after third step
here you have a "printMessage()" invocation.It is overridden in child class Sub
So Sub class method is executes and prints Sub class's variable x value,which is now assigned as 0 only.
So the out put now "Sub.x = 0".
and Base class int x = 20;
Sub class int x = 0;
Step 4.Execution of instance variables and instance blocks in child class.
After 4th step
Base class int x=20;
Sub class int x=30;
Step 5.Execution of child constructor.
After 5th step.
In Sub class constructor you have "printMessage()" method invocation.So it will executes and prints output.
So the out put now "Sub.x = 30".
After the method invocation you have an assignment.
So now Base class int x=20;
Sub class int x=40;
For now your Sub class constructor created successfully.
Now you a print statement of variable x on type reference "Base".So now "Base" class variable x will be prints as output.
So the out put is "20".
By convention, a static method specifically in Java can have access only to static fields or other static methods. The following simple code snippet however appears to violate the convention. Let's consider the following simple code snippet in Java.
class Super
{
protected static int x;
protected static int y;
public Super(int x, int y)
{
Super.x=x;
Super.y=y;
}
public static int sum()
{
return(x+y);
}
}
final class Sub extends Super
{
public static int temp=100;
public Sub(int x, int y)
{
super(x, y);
}
public void concreateMethod()
{
System.out.println("\nInstance variable x = "+x);
System.out.println("Instance variable y = "+y);
}
}
final public class Main
{
public static void main(String[] args)
{
Sub s=new Sub(10, 5);
System.out.println("\nAssociating with object x = "+s.x);
System.out.println("Associating with object y = "+s.y);
System.out.println("\nAssociating with class name x = "+Sub.x);
System.out.println("Associating with class name y = "+Sub.y);
System.out.println("\nSummation (Associating with object) = "+s.sum());
System.out.println("Summation (Associating with class name) = "+Sub.sum());
System.out.println("\nAssociating with class name temp = "+Sub.temp);
System.out.println("Associating with object temp = = "+s.temp);
System.out.println("\nConcreate method called.");
s.concreateMethod();
}
}
The above code produces the following output with the respective statements.
Associating with object x = 10
Associating with object y = 5
Associating with class name x = 10
Associating with class name y = 5
Summation (Associating with object) = 15
Summation (Associating with class name) = 15
Associating with class name temp = 100
Associating with object temp = = 100
Concreate method called.
Instance variable x = 10
Instance variable y = 5
The static fields s and x are being accessed through the following statements within the main() method using the object of the Sub class, though they are declared as static in the super class Super.
Sub s=new Sub(10, 5);
System.out.println("\nAssociating with object x = "+s.x);
System.out.println("Associating with object y = "+s.y);
The following statements of course, have no doubt.
System.out.println("\nAssociating with class name x = "+Sub.x);
System.out.println("Associating with class name y = "+Sub.y);
Since x and y are static, they can certainly be accessed in this way.
The same is the method call, observe the following statements.
Sub s=new Sub(10, 5);
System.out.println("\nSummation (Associating with object) = "+s.sum());
System.out.println("Summation (Associating with class name) = "+Sub.sum());
Both of the ways, the static method sum() is being accessed using the object of the class Super and also using the class name Sub.
Again the similar case with the static field temp declared within the Sub class
System.out.println("\nAssociating with class name temp = "+Sub.temp);
System.out.println("Associating with object temp = = "+s.temp);
The static field temp is being accessed in both the ways.
Why is this happening here?
Basically it's a flaw in the design of Java IMO which allows static members (methods and fields) to be referenced as if they were instance members. This can be very confusing in code like this:
Thread newThread = new Thread(runnable);
newThread.start();
newThread.sleep(1000);
That looks like it's sending the new thread to sleep, but it actually compiles down into code like this:
Thread newThread = new Thread(runnable);
newThread.start();
Thread.sleep(1000);
because sleep is a static method which only ever makes the current thread sleep.
Indeed, the variable isn't even checked for non-nullity (any more; it used to be, I believe):
Thread t = null;
t.sleep(1000);
Some IDEs can be configured to issue a warning or error for code like this - you shouldn't do it, as it hurts readability. (This is one of the flaws which was corrected by C#...)
There is no problem there. Static methods can only access static fields and call other static methods as you have stated. Nothing in your examples does otherwise.
Non-static methods can access both static and non-static methods and fields. Again, none of your examples violate that.
The Sub.temp and s.temp are equivalent and you can use both, it means the same. But 1st is better one because suggests it's a static field.
a static method specifically in Java can have access only to static fields or other static methods declared within the same class
Or its superclass.
I don't see any violation here, you can access static fields/methods via its concrete object or class name. both refer to the same thing.
Where do you see a non-static field or method being accessed by static code? Everything seems perfectly fine to me.
Perhaps what's confusing you is that static fields and methods can be accessed through instances as well as through the class name? It's certainly a big ugly and many consider it bad design, but that's all.