I'm facing some difficulties while trying to understand, what actually happens when we initiate an instance of a child class.
public class A {
2. public int x, y;
3. public A () { x=1; y=2; }
4. public int getx () { return x; }
5. }
6. public class B extends A {
7. public int x, z;
8. public B () { super(); x=3; y=4; z=5; }
9. public int getx () { return x; }
10. public int getz () { return z; }
11. }
12. public class Prob1 {
13. public static void main (String[] args){
14. A o1 = new A();
15. A o2 = new B();
16. B o3 = new B();
17. System.out.println(o1.x);
18. System.out.println(o1.getx());
19. System.out.println(o1.y);
20. System.out.println(o1.getz());
21. System.out.println(o2.x);
22. System.out.println(o2.getx());
23. System.out.println(o2.y);
I would love to here a detailed explanation of what is going on here exactly, but the main thing I can't understand is why line '21' prints the number 1, and line '23' prints the number 4.
Polymorphism applies to methods, not to instance variables.
Both lines 21 and 23 print the value of the instance variables of class A, since that's the compile time type of o2 (even though its runtime type is B).
21. System.out.println(o2.x);
The value of A's x member is 1 (set by the constructor public A () { x=1; y=2; }).
23. System.out.println(o2.y);
The value of A's y member is 4 (set by the constructor public B () { super(); x=3; y=4; z=5; }).
Note the B has an x instance variable that hides A's variable of the same name. Therefore B's constructor doesn't change A's x variable to 3. On the other hand, B doesn't have a y instance variable, so y=4; changes the value of A's y variable to 4.
BTW, line 20 has a compilation error. I had to comment it out in order to execute your code.
Also note that o2.getx() gives a different result than o2.x, since getx() is a method overridden by class B, so it returns B's instance variable x, whose value is 3 (since the runtime type of o2 is B).
Related
Consider below code
class A
{
int x = 5;
void foo()
{
System.out.println(this.x);
}
}
class B extends A
{
int x = 6;
// some extra stuff
}
class C
{
public static void main(String args[])
{
B b = new B();
System.out.println(b.x);
System.out.println(((A)b).x);
b.foo();
}
}
Output of the program is
6
5
5
I understand the first two but can't get my head around the last one. How does b.foo() print 5. B class will inherit the foo method. But shouldn't it print what b.x would print? What exactly is happening here?
Yes, the B class inherits the foo method. But the variable x in B hides the x in A; it doesn't replace it.
This is an issue of scope. The foo method in A sees only the variables that are in scope. The only variable in scope is the instance variable x in A.
The foo method is inherited, but not overridden, in B. If you were to explicitly override foo with the same exact code:
class B extends A
{
int x = 6;
#Override
void foo()
{
System.out.println(this.x);
}
}
Then the variable that would be in scope when referred to by this.x would be B's x, and 6 would be printed. While the text of the method is the same, the reference is different because of scope.
Incidentally, if you really wanted to refer to A's x in the B class, you can use super.x.
Well, this is because of static binding.
1) Static binding in Java occurs during Compile time while Dynamic
binding occurs during Runtime.
2) private methods, final methods and static methods and variables
uses static binding and bonded by compiler while virtual methods are
bonded during runtime based upon runtime object.
3) Static binding uses Type(Class in Java) information for binding
while Dynamic binding uses Object to resolve binding.
4) Overloaded methods are bonded using static binding while overridden
methods are bonded using dynamic binding at runtime.
Fields are not overridable in Java and subclasses with same field names as the parent class shadow "only" the fields of the parent class.
So this.x refers to the x defined in the current class : A.
Whereas the result : 5.
To be more precise : the foo() method is inherited by the B subclass but it doesn't mean that the behavior of the inherited method will change about instance fields referenced since as said fields are not overridable : the this.x expression that refers the A.x field in the foo() method goes on referencing A.x.
It is exactly the same thing as for the two previous statements :
B b = new B();
System.out.println(b.x); // refers B.x -> 6
System.out.println(((A)b).x); // refers A.x -> 5
b.foo(); // refers under the hood A.x -> 5
The very good answer of rgettman shows how you can overcome the field hiding in the subclass.
A alternative to overcome the hiding relies on making the instance field private (which is recommended) and providing a method that returns the value.
In this way you benefit from the overriding mechanism and the field hiding is not an issue any longer for clients of the classes :
class A
{
private int x = 5;
int getX(){
return x;
}
void foo()
{
System.out.println(this.getX());
}
}
class B extends A
{
private int x = 6;
int getX(){
return x;
}
}
In JAVA, methods can be overridden while variables can't. So, as your method foo is not overridden in B, it takes the member variable from A.
When you call
b.foo();
It checks to see if B has overridden the method foo(), which it has not. It then looks one level up, to the superclass A and invokes that method.
You have then invoked A's version of foo() which then prints out
this.x
Now, A can not see B's version of x.
In order to solve this, you have to override the method in B
class B extends A
{
int x = 6;
#Override
void foo()
{
System.out.println(this.x);
}
}
Now, calling
b.foo();
will call B's version of foo() and you will get the expected result.
The question is from the famous SCJP 6 book
Given:
public class Dark {
int x = 3;
public static void main(String[] args) {
new Dark().go1();
}
void go1() {
int x;
go2(++x);
}
void go2(int y) {
int x = ++y;
System.out.println(x);
}
}
What is the result?
A. 2
B. 3
C. 4
D. 5
E. Compilation fails
F. An exception is thrown at runtime
The answer according to the book is:
✓ E is correct. In go1() the local variable x is not initialized.
My questions is why go1() cannot use instance variable x initialized as 6 on line 4 here?
Because the local variable x exists. If int x; were commented out, it will run fine and use the instance variable.
In Java all the local variables should be initialized if not it will give an error. But you shouldn't initialize parameters of a method.
if you don't have int x then this will be ok. because at that case compiler will use the local variable which is assigned for class level.
I have a below code. The variable c and d are class variables and initially they were pointing to value 0, but when I did c=a* a; and d =b* b*b they printed value as 25 and 64 which is correct. so what I think now is that the c and d are now pointing to value 25 and 64 and they are class variables, so if I do j=c+d; it should give me 89 as j value, but it is giving me 0... why? I know if I use static with c and d variable it will give me 89 value... but why I should use static as c and d are global variables and there values are now updated to 25 and 64. Please let me know. Thanks.
public class BaiscSum {
int a=5;
int b=4;
int c;
int d;
int j;
public void square() {
c=a*a;
System.out.println(c);
}
public void cube() {
d=b*b*b;
System.out.println(d);
}
public void sum() {
j=c+d;
System.out.println(j);
}
public static void main(String[] args) {
BaiscSum squ= new BaiscSum();
squ.square();
BaiscSum cub = new BaiscSum();
cub.cube();
BaiscSum su = new BaiscSum();
su.sum();
}
}
You are using three separate instances of your class. This means that squ, cub, and su each have their own version of the class. Instead, use the same one instance, so that all changes will happen to the same instance.
public static void main(String[] args) {
BaiscSum sum= new BaiscSum();
sum.square();
sum.cube();
sum.sum();
}
If I do j=c+d; it should give me 89 as j value, but it is giving me
0. why?
Because you are referencing sum() with su object but you have not called cube() and square() on su instead you called it with cub and squ respectively.
Change to
BaiscSum su = new BaiscSum();
su.square();
su.cube();
su.sum();
It will give you the expected output.
Since all the variables you are using are instace so every object will have its own set of variable on their respective memory spaces and if you changed any one objects variable it will not effects other objects value.
This could clear more
As an explanation every object is assigned a seperate memory and so changes to the variable of one objects doesn't effect changes to other objects variable unless they are static. So in the third object c and d is not initialized for su object so jvm uses default value if int ie 0 giving you a sum of zero.
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.
I have the following code:
import java.lang.*;
public class Program
{
public static void main(String [] args)
{
B a = new A();
a.p(10);
a.p(10.0);
}
}
class B {
public void p(double i)
{
System.out.println(i*2);
}
}
class A extends B{
public void p(int i)
{
System.out.println(i);
}
}
When I execute this code using B a = new A() , I get 20.0 in both cases which makes sense because overloading is handles during compile time where the compiler looks at the declared type and calls a function appropriately. Since our declared type was class B, class B's method was called in both cases. Now if I do A a = new A(); , I should be getting 10 in both answers but I am not. I am getting 10 for a.p(10) and 20.0 for a.p(10.0). Based on the concept of static binding and whole notion of overloading being done by static binding which looks at the declared type as opposed to the actual type, why is the result coming out this way ? I would very much appreciate your help.
An int can be widened to a double, but not the other way around. This means that 10 can call B.p(double) or A.p(int) but 10.0 is a double and will not be implicitly converted to an int i.e. only B.p(double) will be called.
Its because your method p is not an overridden method, it is just inhereted in your sub-class when you use
Super sup = new Sub();
sup.p(int);
sup.p(double);
In this case as your Super class has a method which takes double as a parameter and aa an int can fit into a double your Super-class's method is invoked the one which accepts double.
Sub sup = new Sub();
sup.p(int);
sup.p(double);
In this case however, as your subclass doesn't have a method which takes a double, for sup.p(double) call it uses the inherited method from super class if you pass double as an argument.
In your case, your are doing overloading which will get binded at compile time(static binding.).And static binding happens with type of reference rather than the type of object the reference is pointing.
In your first case you are using a reference variable of B and assigning an object of A to it.Since your reference is B, the method p(double) from B will get binded statically even if you use an int(since int can be widened to double).
In the second case you are using reference as A itself.In this case, you have two p() methods available.One is p(double) from B and other p(int) from A.So p(10) will call p(int) and p(10.0) will call p(double)
Try this:
class B {
public void p(String i)
{
System.out.println("parent:"+i);
}
}
class A extends B{
public void p(int i)
{
System.out.println(i);
}
}
public class Test1 {
public static void main(String args[]) {
A a = new A(); //arg
a.p(10);
a.p("sample");
}
}
If you change the line marked arg to B a = new A(), you will see compiler trying to call parent p in both the cases.
When you write A a = new A() you create a new object of type A, which will have 2 methods. A.p(int) and B.p(double), and when you call A.p(10.0), it will call B.p(double) due to lack of conversion.
This counter-example might help:
import java.lang.*;
public class X
{
public static void main(String [] args)
{
B c = new A();
c.p(10);
c.p(10.0);
c.p("AAA");
((A)c).p(10);
}
}
class B {
public void p(String s)
{
System.out.println("B: my string is " + s);
}
public void p(double i)
{
System.out.println("B: twice my double is: " + i*2);
}
}
class A extends B{
public void p(int i)
{
System.out.println("A: my number is " + i);
}
}
Output:
C:\temp>java X
B: twice my double is: 20.0
B: twice my double is: 20.0
B: my string is AAA
A: my number is 10
The issue is:
1) You're declaring the type as "B" (not "A")
2) B.p(10) can accept an int as a floating point argument
3) Consequently, that's what you're getting
It's really an issue of what argument types can be implicitly converted, than what methods are overloaded or overridden.
When the object has declared type B, the double version is invoked because it's compatible with an int argument, since in Java int is a subtype of double.
When the object is declared as a A, it has the method p() overloaded with two versions:
p(int arg);
p(double arg);
So, when you pass an int, the first version is picked because it's more accurate, and when you pass double the second one, because it's the most specific signature.
For reference, see the relevant JLS at §15.12.2 and this post by Gilad Bracha. BTW, don't try to figure out how the language should behave based on what you think is the most logical way, because every programming language is an engineering effort, and this means that there's a price you pay for whatever you take. The primary source of information for Java are the JLS, and if you read it carefully, you'll (surprisingly?) discover that there are even cases where the line in the source code is ambiguous and cannot be compiled.
To make the effect of widening of int to double more vivid I have created another example which is worth looking. Here, instead of double I have created a class called Parent and instead of int a Child class is created.
Thus,
double ~ Parent int~Child
Obviously child object can be widened to Parent reference.
package test;
public class OOPs {
public static void main(String[] args) {
Child ch = new Child(); // like int 10
Parent pa = new Parent();// like double 10.0
B a = new A(); // case 2 : A a = new A();
a.p(ch);// 10
a.p(pa);// 10.0
}
}
class B {
public void p(Parent i) {
System.out.println("print like 20");
System.out.println(i.getClass().getName());
}
}
class A extends B {
public void p(Child i) {
System.out.println("print like 10");
System.out.println(i.getClass().getName());
}
}
class Parent {
String name;
Parent() {
name = "Parent";
}
public String getName() {
return name;
}
}
class Child extends Parent {
String name;
Child() {
name = "Child";
}
public String getName() {
return name;
}
}
Case 1 - Output (B a = new A();)
print like 20
test.Child
print like 20
test.Parent
Case 2 - Output (A a = new A();)
print like 10
test.Child
print like 20
test.Parent