Down casting object and calling method - java

public class ExampleClass {
public static void main(String[] args) {
// Upcasting from subclass to super class.
A aRef=new C();
//aRef.setMessage(); compilation Error
aRef.display();
B bRef = (B)aRef;
//bRef.setMessage(); compilation Error
bRef.display();
C cRef = (C)aRef;
cRef.setMessage("ayaz");
cRef.display();
}
}
interface A
{
void display();
}
class B implements A
{
public void display() {
System.out.println("Am in class B");
}
}
class C extends B
{
String msg = "Am in class C";
#Override
public void display() {
System.out.println(msg);
}
public void setMessage(String s){
msg = s;
}
}
In the above code after downcasting aRef object to an object of type B unable to call setMessage(),though on calling display with bRef Obj, display method of C class is called. When we downcast to Obj of C then we are able to call why? is aRef only pointing to an object of type C, I think reference is not copied.

Two things:
at compile time the compiler looks at the type of the reference to determine if the method exists (is at least declared). So aRef.display() is correct as bRef.display() and cRef.display(). But aRef.setMessage() and bRef.setMessage() are incorrect (setMessageis not a method declared or defined in A or B. Of course cRef.setMessage() is correct.
at runtime the machine finds the correct method to execute. As aRef, bRefand cRef refer to the same C object that redefines the method display, this one is called.

Although the Object which resides in the heap is of Class C,the reference you have used is of Type B.You can only call the methods which exist in the reference and not the methods present in the actual Object.
1)Only Class C has setMessage method.So only a reference of Object C can invoke this method.Alternatively you can define these methods in interface and Class B and mark Class B as abstract with a concrete implementation in Class C
public class ExampleClass {
public static void main(String[] args) {
// Upcasting from subclass to super class.
A aRef=new C();
aRef.setMessage(); //No compilation Error now
aRef.display();
B bRef = (B)aRef;
bRef.setMessage(); //No compilation Error now
bRef.display();
C cRef = (C)aRef;
cRef.setMessage("ayaz");
cRef.display();
}
}
interface A
{
void display();
void setMessage(String s);
}
abstract class B implements A
{
public void display() {
System.out.println("Am in class B");
}
}
class C extends B
{
String msg = "Am in class C";
#Override
public void display() {
System.out.println(msg);
}
public void setMessage(String s){
msg = s;
}
}

The simple rule is:
The type of the variable tells what can be done
The type of the object tells how to do it

Related

Use of shadowed object variables give unexpected and unexplained results

public class Test {
public static void main(String[] args) {
Super s = new Sub();
System.out.println(s.a); //Super-Attribut
System.out.println(s.m1()); //Sub-Attribut
System.out.println(new Sub().m2()); //Super-Attribut
}
}
class Super {
String a = "Super-Attribut";
String m1() {
return a;
}
String x() {
return a;
}
}
class Sub extends Super {
String a = "Sub-Attribut";
String m1() {
return a;
}
String m2() {
return x();
}
}
I have a question regarding the above code, especially the line System.out.println(new Sub().m2()). In this line an instance of the class Sub is created. On this instance the function m2() in the class Sub is called. The method m2() in Sub calls the method x() in Super. The method x() returns the string variable a.
Shouldn't this a be the a, which is declared in the class Sub, since an object of the class Sub is being used, i.e the runtime type is Sub, and also the declaration type or the static type of the used object, which is new Sub(), is Sub?

Cannot get value of property from extending class

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]

When does the constructor initiallize?

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.

About Method Overloading in Java

Can method overloading take place only within the same class? Or can it take place within sub classes?
There is no restriction on overloading within sub-classes. For example, I could have:
public class A {
public String test(String input) {
//do something
}
}
public class B extends A {
public String test(String input, String input2) {
//do something
}
}
B testInstance = new B();
testInstance.test("one", "two");
testInstance.test("one");
For questions like this, you can always try it yourself and find out.
In a word - yes. You can overload methods in a subclass. E.g.:
public class Parent {
public void print(String s) {
System.out.println("That was a string: " + s);
}
}
public class Child extends Parent{
public void print(int i) {
System.out.println("That was an int: " + i);
}
}
public class Main {
public static void main(String[] args) {
Child c = new Child();
c.print("hello"); // prints "That was a string: hello"
c.print(7); // prints "That was an int: 7"
}
}
When you overload a method, it's basically creating an entirely new method with no direct association with the other of the same name, it's the signature that matters.
so if you make a method in the subclass that has different signature it will be treated as different and new method for that class by the compiler so it won't be relating it to the method of super class.
Overloading can be possible in sub classes. If you create a method with the same name as in super class with different parameter then it will be treated as separate method. Sub class will have methods from super class as well so which method to be called is decided at compile time based on the parameter type. Which method to be called is declared at compile time that is why it's called static polymorphism. Here is the example -
Class A{
void m1(int x){
System.out.println("m1 in A");
}
}
Class B extends A
{
void m1(String str)
{
System.out.println("m1 in B");
}
}
Public Class Test
{
public static void main(String[] aa)
{
B b = new B();
b.m1(10);
b.m1("Hello World!!")
}
}
Hope this will help.

When is an Object created after a constructor is called

Consider the following code classes.
public class A
{
public A()
{
callCreation();
}
protected void callCreation()
{
System.out.println("A Created!!");
}
}
public class B extends A
{
protected void callCreation()
{
System.out.println("B Created!!");
}
}
public class C extends B
{
protected void callCreation()
{
System.out.println("C Created!!");
}
public static void main(String[] args)
{
A a = new A();
A b = new B();
A c = new C();
}
}
The output of running the class C is given below.
A Created!!
B Created!!
C Created!!
The first output line in the output A Created!! is printed because when the constructor of class A is called, it calls the super class's constructor (java.lang.Object) implicitly before calling the callCreation() method in the class A's constructor. And this will be the case for B and C classes too. In that case when the constructor of B is called the call flow should be typically : B's constructor -> A's Constructor -> java.lang.Object's Constructor -> come back to A's callCreation() method to finish calling A's constructor. If so how is the overridden value printed and not the super class's value is printed? So the question is 'when is an object of a class created exactly? to put it in other words, the object of a class should be created only after the constructor finishes calling/initializing all the elements within itself. If so how can a method be called from a child class and not from the parent class?
The callCreation methods in B and C override the method from A. So when the method is called in the constructor A the implementations in B and C will be run, even though the constructors of B and C have not been executed yet. This is possible because constructors don't actually create the object, rather they are called to initialize some moments after the JVM has created it.
In general it's a very bad idea to call methods that can be overridden from a constructor for this very reason. A method in B or C may assume that the constructor and object initializers have already been run, and read an unexpected value from a field. For example the following ends up printing "B Created!! null" because the field still has not be assigned its value.
public class B extends A
{
final String msg = "Yes!";
protected void callCreation()
{
System.out.println("B Created!! "+msg);
}
}
thinking in this way makes it more obvious:
when an object of type B is being created super() keyword calls the A constructor,
then in A constructor "this.callCreation()" is executed, which refers to the current
object which is B, so callCreation corresponding to the current object(B) is called.
the same process is done for C.
public class A {
public A() {
this.callCreation();
}
protected void callCreation() {
System.out.println("A Created!!");
}
}
class B extends A {
public B() {
super();
}
protected void callCreation() {
System.out.println("B Created!!");
}
}
class C extends B {
public C() {
super();
}
protected void callCreation() {
System.out.println("C Created!!");
}
public static void main(String[] args) {
A a = new A();
A b = new B();
A c = new C();
}
}

Categories