I'm learning Java and I'm doing this exercise and I have to say what the main method prints. Its goal is to better understand Java inheritance.
interface X extends Remote{
A m(B bb) throws RemoteException;
}
class A implements Serializable{
int a;
A m(A aa){
aa.a = 3;
System.out.println("A.m");
return aa;
}
}
class B extends A{
int b;
A m(B bb){
bb.b = 7;
System.out.println("B.m");
return bb;
}
}
class C extends A implements X{
public B m(B bb){
if(bb.b == 7) bb.b = 9; else bb.b = 1;
System.out.println("C.m");
return bb;
}
}
Now I have a main method in which I call:
X x = new C();
B b = new B();
(x.m(b)).m(b); // prints C.m() A.m()
The third line of my main method, prints "C.m() A.m()" but I don't understand why it prints A.m(). The x.m(b) returns an object that has both static and dynamic type == B; on this object it is invoked m(b) method; so why it is not called the m() method of B class?
I've seen that the m() mehtod in B class is not an overriding of the m() method in A class because they have different explicit parameter.
thanks in advance
b in an instance of B, which extends A. As such, B has 2 m methods.
To know which is called, what is important is the type of the object on which the method is called.
(x.m(b))
is the result of the call to the m method from the X interface, because the declaring type of x is X.
Therefore (x.m(b)) is an object of type A (even though the actual implementation is a B).
This being a type A, the m method from the A class is called.
If you change the names of the methods, it will become clearer that the m methods from A and B are really different objects.
Your mistake is assuming that
The x.m(b) returns an object that has both static and dynamic type == B;
Which is wrong, because x is declared of type X, making the result of x.m a type A.
Related
This question already has answers here:
Does polymorphism apply on class attributes in Java?
(8 answers)
Closed 4 years ago.
I have the following program :
class A{
int b = 50;
}
class B extends A{
int b = 20;
}
public class Maini{
public static void main(String[] args){
A a = new B();
System.out.println(a.b);
}
}
and the result is 50 and I would like to know why?
before I run the code I am pretty sure that the result should be 20.
This has nothing to do with how constructors work.
Note that the member variable b in class B does not override the member variable b in class A. Only non-static, non-private methods can be overridden. Member variables cannot be overridden.
If you have an instance of class B, then it actually has two member variables called b: one in the superclass (A) part of the object, and one in the subclass part (B).
The reason that you see the value 50, which is the value of b in the A part of the object, is because the variable a in the main method is of type A. If you change this to B, you'll get 20:
B a = new B(); // instead of A a = ...;
In the statement
A a = new B();
You are calling Bs constructor in an object of type A
In your program, you have given no constructor to B, so it looks to A.
In A, the value of int b is 50 and an object is of type A, hence the value is chosen as 50
If you had a constructor in B e.g.
B() { b = 20;}
the value would be 20.
You think that you are creating a B but you have not written any constrcutors for the class B so it looks to the super() constructor which is it's parents (A). So you now have an object of A. If you are curious about why A's object isi being created while there is no constructor to it too. A calls to it's super constructor too which is Java's Object Class's constructor.
I hope that I could make this point clear.
use a intellitrace enabled IDE for better experience of coding.
1st of all you'l hav a default constructor if you are not imposing on it.
Secondly you are defining an object of type 'A' not 'B'. if you want the output as 20 then you hav to include this B() {int b = 20;}.
Here in this code Sniplet there is no constructor in Any class.
So JVM will create no argument default constructor in all classes.
While you are Running this then .
In the below code you
a is referring class A and having object of class B
A a = new B();
So here the Object a will have class A 's variable value.
and Class B object value as its calling Class B 's default constructor(new B();)
If Class A and B have same Method like below Example:
class A{
int b = 50;
void method(){
System.out.println("Method of A class");
}
}
class B extends A{
int b = 20;
void method(){
System.out.println("Method of B class");
}
}
public class Maini{
public static void main(String[] args){
A a = new B();
System.out.println(a.b);
a.method();
}
}
Then a.method() will print
50
Method of B class
as a is have Class B 's object.
When you write A a = new B() the object a is type A. This is why you're getting b = 50. If you want to get b = 20, you need to declare a as a B class
Hope it's clear enough.
Best
class A{
int foo=10;
}
class B extends A{
int foo=10;
}
class Test{
public static void main(String [] args){
A a=new B();
System.out.println(a.foo);
//System.out.println(a.getClass());
}
}
In this case 10 is output. If I am not wrong, then this is because the a variable is of type A and variable assignment is static binding, and static binding is done at compile time by looking at the type of the variable. Since here a is of type A, then A's int foo is called. However when I call
System.out.println(a.getClass());
then this gives class B, that is a is of type B. I am confused about this. Kindly explain to me a is of which type and how A's int foo is printed.
But by looking at this code
class A{}
class B extends A{}
class Test{
public static void main(String [] args){
B b=new B();
A a=b;
B b1=(B)a; // compiles and run fine (a is of type B)
}
}
How is this possible? What's happening here? First b is of type B then in the second line a becomes of type A, as A a=.. is written but a.getClass() gives that it is of type B. How? If a is of type B then why is it calling A's int foo in the first example? Kindly explain both examples.
Also, does type casting change references or do any other stuff?
An important thing to realise is that Java only has primitive and reference variable types. This means when you write
A a =
The a is just a reference to an object (or null) not an object.
When you do
A a = new B();
there is no cast here, no work is done, no object is harmed or changed.
When you call an instance method on a class, it calls the method for the class of the object.
Object o = new B();
assert o.getClass() == B.class;
a longer example
B b = new B();
A a = b;
assert a == b; // always true as they point to the same object.
assert b.getClass() == B.class;
// so it makes sense that since a == b
assert a.getClass() == B.class;
type casting change references or do any other stuff?
It changes the type of the reference and it doesn't do other stuff like change the type of the object.
methods follow inheritance, however fields follow the type of the reference as a field cannot be overridden, it can only be hidden.
B b=new B(); A x=b; B b1=(B)x; // compiles and run fine (x is of type b) in this line when x is of which type
correct and you wouldn't be able to (B)x unless x was a reference to a B The variables x is an A which means it must point to an A object or a sub-class of a A e.g. B you can write
B b = new B();
A x = b;
assert x == b; // they still point to the same object.
B b1 = (B) x;
assert b1 == b; // same object
assert x == b1; // same object.
No new objects are created, nor is the object changed.
Quite simple why it does print the foo of A, because a is defined as A. Since there is no overriding for variables you are simply accesing the variables which are accesible for the type the variable is declared, which is A in this case.
public static void main(String[] args) {
A a = new A();
System.out.println(a.foo); // prints the foo of A, since a is of the type A
A b = new B();
System.out.println(b.foo); // prints the foo of A, since b is of the type A
B c = new B();
System.out.println(c.foo); // prints the foo of B, since c is of the type B
}
In the end it´s called shadowing what you are doing there. Your class B has a variable with the same name as A. Since they are not overridable you are able to hide foo of A, if your variable is of the type B, where you are accessing foo of B
Your question is related to Javas polymorphic behavior and dynamic (late) vs. static (early) binding.
The access to all the member variables in Java follows static binding. That means you have no polymorphism in this case. Instance Methods are dynamically bound. The instance method used for an invocation will be determined by the class of the object, not by the reference type. For example:
public class Main {
static class A{
String foo="A";
public String getFoo() {
return foo;
}
}
static class B extends A{
String foo="B";
#Override
public String getFoo() {
return foo;
}
}
public static void main(String[] args) throws Exception {
A a=new B();
System.out.println(a.foo); // prints A
System.out.println(a.getFoo()); // prints B
System.out.println(a.getClass()); // prints Main$B
}
}
Late binding
Early Binding
Polymorphism
In the following code, I don't understand why when a1.k() is called, this.x in class C returns 100 instead of 1. My understanding is that this refers to the current object, but the static type of the current variable a1 is A. So shouldn't this.x returns 1, which is the variable for A type?
I mean a1.x should return 1, right? Many thanks!
class A {
public int x = 1;
public String k() { return "A" + this.x; }
}
class B extends A {
public int x = 10;
...
}
class C extends B {
public int x = 100;
public String k() { return "C" + this.x; }
}
class TestABC {
public static void main(String[] args) {
A a1 = new C();
C c1 = new C();
System.out.println(a1.k());
}
}
When you call a1.k() you dynamically dispatch to the k method that is defined by the actual object whose reference is in a1. In this case, it is a C not an A or a B, and hence the k method is the override defined in C.
The static type (of a1 for example) is used for static resolution; e.g. resolving static methods, overload signatures, and fields. But for instance method invocation, the ultimate selection of the method to be invoked is dynamic.
I know the k() in class C should be called, instead of the k() in class A. But why this.x returns 100? I thought the instance variable is bounded to the static type.
Well it is. But it is the static type that determines which x is used by this.x in the k() call is the static type of this in the C.k method body!
This feature is called Dynamic Polymorphism. The methods being called is not dependent of type of its declaration but by the type being assigned to it (definition).
For this the classes must inherit and also override the methods in the parent class.
Here C,B extends A and overrides the method k;
if you try to call some C specific methods or variable it will throw error. (Since A doesn't know about that)
A is holding reference to C (pointing to C)
a1.k is actually C constructed Object and its new C().k() where x is 100 in C.
class Base{
int x=10;
public int getx(){return x;}
}
class Sub extends Base{
int x=100;
public int getx(){return x;}
}
class Test
{
public static void main (String[] args)
{
Base b = new Base();
Sub s = new Sub();
System.out.println("sub: getx:"+s.getx()+" .x:"+s.x+" Class: "+s.getClass().getName());
System.out.println("base: getx:"+b.getx()+" .x:"+b.x+" Class: "+b.getClass().getName());
Base btoS = new Sub();
System.out.println("btos: getx"+btoS.getx()+" .x:"+btoS.x+" Class: "+btoS.getClass().getName());
}
}
Results in
sub: getx:100 .x:100 Class: Sub
base: getx:10 .x:10 Class: Base
btos: getx100 .x:10 Class: Sub
Since you declare a1 as new C(), a1 will be seen as an object instance of class C, which overrides the fields of its parent class B and A. So why you would do things like A a1 = new C(); (or you might see a lot of such implementation), there is a recommendation saying "programming to interface rather than the actual implementation.", and I think this explains better.
In a situation like this:
class A{
public int x = 4;
public void s3(){
x = 3;
}
public void f(){
x = 8;
s3();
}
}
class B extends A{
public int x = 5;
public void f(){
x = 10;
s3();
}
}
A a = new B();
B b = (B) a;
a.f();
System.out.println(b.x);
System.out.println(a.x);
a.f() calls the f() of the class B, then f(), after an assignment, calls the s3() function. At this point, s3() is only defined in A and when it assigns the value 3 to x, x is the copy of the variable owned by the class A. Why s3() doesn't use the x declared in B? In theory, B shouldn't has its own copy of s3() function inherited from A? (so the s3() inherited from A in B should use the x declared in B)
You have a misunderstanding of what you should be doing in inheritance. extends is a reserved word that was wisely chosen. The point of B extending A is to say that B is a subset of A with additional attributes. You're not supposed to redefine x in B; A should be handling x. By redefining x in a subclass, you're hiding the superclass' field x (this is true even if x refers to different variable types).
A a = new B();
System.out.println(a.x); //4 makes sense, since we are of class A
B b = (B) a;
System.out.println(b.x); //5 makes sense, since we are of class B
a.f();
System.out.println(a.x); //3 makes sense, since a.f() calls s3(), which sets A's x to 3
System.out.println(b.x); //10
The 10 follows from printing b's x, which is assigned to 10 with the call of a.f(), which then calls s3() which is why the 3rd example prints 3. To see what I mean look at this:
public void f()
{
x = 10; //sets B's x to 10
s3(); //calls A's s3(), which sets A's x to 3.
}
Because it is the same. You do not have two copies ("instances") of the object, only one.
Since the one you create is a B instance (new B()), it will be used the methods as defined in B. Of course, when no methods are defined in B it will use the superclass methods implementation.
So, you only have an x attribute and s3 forces it to be 3. It works ok.
Why s3() doesn't use the x declared in B?
Generally, methods in a parent class cannot see member variables in a child class.
I think doing just this:
B b = new B();
b.f();
is enough to reproduce at least part of your confusion. Here is what f() looks like in B:
class B extends A{
public int x = 5;
public void f(){
x = 10;
s3();
}
}
f() is equivalent to:
public void f(){
this.x = 10;
this.s3();
}
So calling b.f() means f() is equivalent to:
public void f(){
b.x = 10;
b.s3();
}
Next, what happens inside the s3() method in A? s3() looks like this:
public void s3(){
x = 3;
}
and that is equivalent to:
public void s3(){
this.x = 3;
}
'this' is the object that called the method, which from the last example of f() you can see is b. So s3() is equivalent to:
public void s3(){
b.x = 3;
}
So b.x gets overwritten with 3...uhhhhm not so fast!
An instance of B also inherits an x from A, it's just that inside B it so happens that B's x shadows the x from A. As a result, the f() method in B assigns to the x from B. Inside s3() however, the x that b got from A is not shadowed anymore, and as far as A is concerned there is only one x--the one from A. In other words, the lookup for b.x takes a different path depending on what class that statement appears in.
After s3() executes, the end result is that b has two x's with two different values. Inside methods in B, the x from B will be visible, and inside methods in A, the x from A will be visible. Inside methods in B, it is possible to get at the the x from A by using super.
In theory, B shouldn't has its own copy of s3() function inherited from A?
Don't think in terms of copies. Think in terms of pointers from class to class, and pointers from classes to lookup tables. Typically in computer programming, each instance has its own instance variables but methods are shared by all the instances in a class.
class A
class A {
int a;
int c;
A (int a, int c) {
this.a = a;
this.c = c;
}
}
class B
class B extends A{
public static void main (String [] args) {
A obj = new A (5, 6);
}
}
When I compile the code It shows me this error
B.java:1: error: constructor A in class A cannot be applied to given types;
class B extends A{
^
required: int,int
found: no arguments
reason: actual and formal argument lists differ in length
1 error
When this error appears exactly? And when inheritance the class Is the constructor must be the same type of super class?
A specifies a constructor taking two arguments, B only specifies a parameterless (the default one).
If you really want to let B inherit from A, you'll need to create a constructor as well, either one with two arguments as well, or one just calling the constructor of A with default values:
// variant A
class B extends A {
B (int a, int c) {
super(a, c);
}
}
// variant B
class B extends A {
B () {
super(0, 0); // replace 0 with an appropiate default value for each parameter
}
}
However, from your code, B wouldn't need to inherit from A, if you only want to instantiate A in the main. Just remove the inheritance in that case.
Add a constructor to class B.
The compiler realizes that you cannot instantiate class B!