Polymorphism: calling subclass' method from superclass' variable - java

In Java, when a method is going to be executed, it's declaration is first searched for at the object's real class (that defines the real type of the object). If it's not found, then the superclass is checked. If isn't found there either, the next parent class is checked, and so on. However, look at the example below:
SuperClass s = new SubClass(list of parameter);
s.someMethodExistOnlyInSubClass();
This will give me a compile time error. I thought that, as mentioned above, it would first look for someMethodExistOnlyInSubClass() at SubClass, verify that it exists there and then execute it right away. If I use a variable of the type SuperClass to reference an instance of SubClass some parameters will go to SuperClass's constructor through a call to super() and the object will be instantiated there. In this context, to where have the remaining parameters gone?

By assigning a reference to an instance of SubClass to a variable of the type SuperClass, the variable is treated as if it were referencing an instance of SuperClass. Therefore, it will have no knowledge of any of the methods declared specifically in SubClass. Note, though, that the overrides performed in SubClass will still be effective.
In the context you described, to access someMethodExistOnlyInSubClass() you would have to cast s to the type SubClass. Look below:
((SubClass) s).someMethodExistOnlyInSubClass();

What you are trying to do will work only when the method is defined in both Parent class and subclass.
import java.util.*;
class Parent
{
public void sample()
{
System.out.println("Method of parent is getting Called");
}
}
class Subclass extends Parent
{
public void sample()
{
System.out.println("Method of Child class is getting Called");
}
}
public class Main
{
public static void main(String[] args){
Parent p = new Subclass();
p.sample();
}
}
OUTPUT : Method of Child class is getting Called
If the method exists only in Child class. You will have to create an instance of Child class itself.
Something like this :
import java.util.*;
class Parent
{
}
class Subclass extends Parent
{
public void sample()
{
System.out.println("Method of Child class is getting Called");
}
}
public class Main
{
public static void main(String[] args){
Subclass p = new Subclass();
p.sample();
}
}
Or you can type cast it as mentioned in the earlier post
Parent p = new Subclass();
((Subclass)p).sample();

An object is created based on its declaring class.
When you declare it as SuperClass s the object s wont have any method called someMethodExistOnlyInSubClass . So when you try to invoke this method, even before look at the subclass, you get a compile error.
The object s contrains only everything of the superclass, this object wont be aware of any subclass until u type cast the object to subclass.

Related

Is it possible for a superclass object to refer a subclass member method which is not inherited?

In dynamic method binding a superclass reference can only call a subclass method which is inherited and overrode by it. However, the otherwise can be implemented.
abstract class in
{
abstract void print();
}
class a extends in
{
String name=this.getClass().getSimpleName();
void show()
{
System.out.println("class "+name);
}
void print()
{
show();
}
}
class Main
{
public static void main(String args[])
{
in x;
x = new a();
x.print();
}
}
Here, it prints successfully
class a
Also getClass() returns the subclass name instead of superclass name as this refers to the superclass object in main method.
A parent object reference is just constrained by the methods that it has in its class definition. If those methods are overridden by subclass, and at run time, if the actual object referred by the parent reference is of subclass type, then that overridden method is invoked. It doesn't matter if the overridden method invokes methods that are not originally present in the parent class or accesses the variables that are not present in the parent class.
This is what polymorphism is all about. It is by design meant to be this way as it makes program extension easier in case if we have different specific inheritance hierarchies where the parent class need not know the exact implementation of certain methods and can make things implemented by the subclasses as some sort of contract.
Future is unknown A developer writing a class A.java today can never predict in future the names or signatures of the methods which any other developer may include in his class extending A.java. Also such classes may be numerous with each having separate methods.
Base class should never be coupled with its sub classes. It must not care about how the sub classes are implemented.
Although it is not recommended but still if you wish to invoke the method defined in one of the sub class you may do it by typecasting like below.
public class Parent {
public class someMethod(){
if( this instanceof Child1){
((Child1)this).someAdditionalMethod();
}
}
}
public class Child1 extends Parent{
public class someAdditionalMethod(){
}
}

Difference between super keyword vs class name to call method from super class

Kindly excuse my question as I have tried to search the difference between using super keyword vs class name to call a method from super class but am unable to find an answer.
My question is I am trying to learn Java as a study course and am using an example from the link: http://www.javatpoint.com/super-keyword using Example # 3 and here is the code I have written:
I have created a super class named Vehicle
public class Vehicle {
Vehicle() {
System.out.println("Vehicle constructor created");
}
public void speed() {
int a = 20;
System.out.println(a);
}
}
and then created a sub class named Bike with the following code:
public class Bike extends Vehicle {
int speed;
Bike(int speed1) {
this.speed = speed1;
System.out.println(speed1);
super.speed();
}
public static void main(String args[]) {
Bike b = new Bike(10);
}
}
In the sub class under Bike constructor I am using super.speed() to call speed method from super (Vehicle) class. Now if I change this line to Vehicle.speed() I get an error stating that I need to make my speed method as static.
I do not want to make my method as static and want to know about the difference between both of them.
Cheers,
Calling a method using class name directly means that you want to call a static method, which is not related to any object of the class but the class it self.
That is why the compiler tells you that the method must be static.
As for your question, when you create an object of a child class (Bike class in this example) an object of its parent is always created, on the base of which the particular child object is created.
Its like, when ever you create a Bike, a backing Vehicle is always created, based on which the Bike is created. Otherwise the Bike wouldn't be a Vehicle.
So calling a method by super means, you're telling the compiler to call this method on the class which was used as base(parent) for making this Bike class, from which I'm calling this method.
when you're calling the method by class name, you're telling the compiler to call this method of Vehicle class which is not related to any Vehicle object/instance (and obviously not related to any child (e.g. Bike object or instance as well)
Methods that aren't static can only be called on a specific instance of an object. That is why calling Vehicle.speed() would only work if the speed method were static. The reason you can call super.speed() is because in the constructor, you have already constructed the vehicle object, and are basically calling the method on the object you are constructing.
For the above example, I would say that calling super.speed() is the best approach.
Also, as you haven't overriden the super implementation of the speed method, you can just as easily call this.speed() or speed(). That approach would mean that if you ever decided that the Bike needs different functionality in the speed method, your specific implementation would be called as opposed to the default.
The two constructs are not equivalent.
When calling Vehicle.speed() the compiler is looking for a static method named speed() in the class named Vehicle. A static method doesn't belong to any instance of the class. You cannot use any instance variable inside a static method. You haven't defined a static method named speed() in your Vehicle class and therefore there's no such thing as Vehicle.speed(). Hence, you get a compilation error.
When calling super.speed(), you don't look for a static method as in the previous case: The actual method that is going to be called when using the super syntax is an instance method (named speed() in your case) defined in the superclass of the current object. That is, super.speed() is the instance method defined in the super class of the current object (unlike this.speed() which is the instance method named speed() defined in the actual class of the current object). In other words, it is going to call the method speed() defined in the class Vehicle, but the this parameter is going to be the one referenced by b, the current object.
You need instance to calls instance(non-static) method.
super is parent class's instance. Simply put class name is not an instance(it' a static context for entire class).
[super is parent class's instance ?]
Jon skeet said no such thing as a "parent instance", but i doubt the term of instance.
super's variable is initialized first and then the turns of child to decide whether share the same variable/method(i.e. return this.i; in this kind of method will return super.i, not this.i, when call by child) or override it.
import java.util.Random;
class Love {
int i = 1;
int hole() {
return this.i;
}
}
class Main extends Love {
void wrapper() {
System.out.println(super.i); //1
System.out.println(this.i); //2
super.i = new Random().nextInt(50) + 2; //to avoid compiler pre-optimizing hard coded return value in hole(), so we set again.
System.out.println(super.i); //23
i = 3; //2nd attempt override
this.i = 3; //3rd attempt override
System.out.println(hole()); //23, super "instance" keep its own version of this.i
}
int i = 2; //1st attempt oveeride
public static void main(String[] args) {
new Main().wrapper();
}
}
So it's obvious when child override, super still keep its own version, so IMHO super can roughly treat like a parent instance, just the difference with normal instance are it's a keyword with some restriction of usage (e.g. super.super.i is not allow, direct print super not allow). One more difference is the variable value will sync in each instance due to child might share it as mentioned above.
You can try to print super.variable_name inside static method, it will output super is a non-static variable:
$ javac Bike.java
Bike.java:132: error: non-static variable super cannot be referenced from a static context
System.out.println(super.dummy);
^
Bike.java:132: error: cannot find symbol
System.out.println(super.dummy);
^
symbol: variable dummy
2 errors
$
So it's make sense super as a non-static variable can access non-static method speed() in your example.
If you want to use method directly with class name then you have to specify method as static
public static void speed() {
int a = 20;
System.out.println(a);
}
or
you can create an object of class Vehicle and access speed method in your subsclass like this
Bike(int speed1) {
this.speed = speed1;
System.out.println(speed1);
Vehicle vehicle = new Vehicle();
vehicle.speed();
}
hi super is a keyword which is used to access the super class methods in sub class.
This super keyword is used mainly when methods are overridden.
example
class A
{
method m()
}
class B extends A
{
method m()
method m1()
{
super.m()
}
}
class C
{
public static void main(String args[])
{
B b = new B();
b.m() // calls method m() in class B
b.m1() // calls method m() in class A because method m is pointing to super class method
}
}

the issues of calling overridable methods from constructor

if it is possible please make this sentence clear for me
here, the author said:
Do not call overridable methods from constructors. When creating a
subclass object, this could lead to an overridden method being called
before the subclass object is fully initialized. Recall that when you
construct a subclass object, its constructor first calls one of the
direct superclass’s constructors. If the superclass constructor
calls an overridable method, the subclass’s version of that method
will be called by the superclass constructor—before the subclass
constructor’s body has a chance to execute.
i can't understand that how it can be possible to call a subclass's version of the overridable method in the superclass's constructor
TnX
You have to first make a distinction between instantiation and initialization. Instantiation is the process of creating an instance of a type (allocating the space for it and getting a reference to that space). Initialization is the process of setting the state of the instance to its initial value.
Take the following type hierarchy:
class Foo {
public Foo() {}
}
class Bar extends Foo {
public Bar() {super();}
}
New instance creation expressions
new Bar();
cause instantiation and initialization. Instantiation happens first. Java creates an instance of concrete type Bar.
Then initialization needs to take place. In an inheritance hierarchy, the initialization follows the same hierarchy, but top to bottom.
Object
|
Foo
|
Bar
The constructor for Object runs first to initialize the state that is defined as part of Object, then the constructor for Foo is run to initialize the state that is defined as part of Foo and finally the constructor for Bar is run to initialize the state defined in Bar. Your instance is still of type Bar. So polymorphism still applies. If you invoke an instance method and that method is overriden somewhere lower in the hierarchy, that implementation will be invoked.
That's what that quote is referring to. It's dangerous. Read more here:
What's wrong with overridable method calls in constructors?
To illustrate the reason this is a bad idea with some (simplistic) code, consider these two classes:
class Greeter {
protected Greeter() {
printHello();
}
protected void printHello() {
System.out.println("Hello");
}
}
Looks simple enough, it prints Hello whenever you instantiate it. Now lets extend it:
class NamedGreeter extends Greeter {
private String name;
public NamedGreeter(String name) {
this.name = name;
}
#Override
protected void printHello() {
System.out.println("Hello " + name);
}
}
The intent is clearly to have the NamedGreeter greet you by name when instantiated, but in fact it will always print Hello null because the super constructor is called first when the NamedGreeter is instantiated.
Thanks to how polymorphism works, any time the printHello() method is called on a NamedGreeter (even if that call is from within the Greeter class) the implementation in NamedGreeter will be called. Calling that method from within the constructor of the parent class means that even if the child class extends it then no fields defined by the child will be initialized, simply because it's not possible to do anything in the child constructor (like initialize fields) before the parent constructor is called.
An example demonstrating that the child method will be invoked:
class Foo {
static class Parent {
Parent() {
someMethod();
}
void someMethod() {}
}
static class Child extends Parent {
#Override void someMethod() {
throw new AssertionError("Invoked");
}
}
public static void main(String[] args) {
new Child(); // Throws Exception.
}
}
Output:
Exception in thread "main" java.lang.AssertionError: Invoked
at Foo$Child.someMethod(Foo.java:16)
at Foo$Parent.<init>(Foo.java:9)
at Foo$Child.<init>(Foo.java:14)
at Foo.main(Foo.java:21)

Does creating an instance of a child class automatically create its super class object?

If I create an object of sub class then will the super class object also be created from which the sub class is inherited? If not then how by creating a sub class of Thread class (in multi-threading) calls the Thread class constructor and creates a Thread object?
An instance of the subclass is an instance of the superclass. Only one object is created, but as part of that creation, constructor calls are chained together all the way up to java.lang.Object. So for example:
public class Superclass {
// Note: I wouldn't normally use public variables.
// It's just for the sake of the example.
public int superclassField = 10;
public Superclass() {
System.out.println("Superclass constructor");
}
}
public class Subclass extends Superclass {
public int subclassField = 20;
public Subclass() {
super(); // Implicit if you leave it out. Chains to superclass constructor
System.out.println("Subclass constructor");
}
}
...
Subclass x = new Subclass();
System.out.println(x instanceof Subclass);
System.out.println(x instanceof Superclass);
System.out.println(x.superclassField);
System.out.println(x.subclassField);
The output of this is:
Superclass constructor
Subclass constructor
true
true
10
20
... because:
The first thing any constructor does is call either another constructor in the same class, or a superclass constructor. So we see "Superclass constructor" before "Subclass constructor" in the output.
The object we've created is (obviously) an instance of Subclass
The object we've created is also an instance of Superclass
The single object we've created has both fields (superclassField and subclassField). This would be true even if the fields were private (which they usually would be) - the code in Subclass wouldn't be able to access a private field declared in Superclass, but the field would still be there - and still accessible to the code within Superclass.
The fact that we've got a single object with all the state (both superclass and subclass) and all the behaviour (any methods declared within Superclass can still be used on an instance of Subclass, although some may be overridden with more specializd behaviour) is crucial to understanding Java's approach to polymorphism.
Youre only creating one object when you create a subclass of another. It is an instance of both the subclass and all its parents. Example, I create a cat object. It is a cat, and at the same time a feline, mammal, and animal, and an Object.
When you create an object, it gets one piece of memory with one set of variables to hold the all of its data.
The subclass will contain fields from the child and any fields from its ancestors. So it's a single object that acts like the child and its ancestors. There is no parent class object created when you create a subclass.
No there Is only one Object there. There Is a misconception that constructor is for creating an object. But It actually for initializing an object. So when we created child class object along with the child class constructor the parent class constructor also executed because of the first line of the child class constructor either this() or super(). Now, look at the following code.
Public class P{
public P(){
System.out.println(this.hashCode()); // Parent class Constructor
}
}
public class C extends P{
public C(){
System.out.println(this.hashCode()); // Child Class constructor
}
}
public class Test{
public static void main(String [] args){
C c = new C();
System.out.println(c.hashCode());
}
}
If you run the code you can see There is only one HashCode. and an object just has one hashCode. If the parent class object would be created then there must be another hashCode for that object.
Here I am abbreviating with an example that
If a child class object is created, does it automatically create super class object?
class P{
P(){
System.out.println(this.hashCode()); // it will print 2430287
}
}
class C extends P{
C(){
System.out.println(this.hashCode()); // it will also print 2430287
}
}
public class Test{
public static void main(String... args){
C obj = new C();
System.out.println(c.hashCode()); //Again, it will print 2430287
}
}
If you compile and run this code you will find same Object hashCode is getting printed. So, this means there is only one object is created.
Now, how is the parent class object being initialized?
In this example only one object is created which is an instance of the child class, but there are two constructors (parent and child) being executed. But the constructor are just in context of child class only.
Nope.
It will not create instance of parent class. But certainly it will create an instance.And the object reference passed to child class. Hence instance is created at parent class and invoked by child class constructor. and child class methods operates.

How to call an non overide method of child class using parent object reference

Here is my code want to access child class method of AdapterVer1 getAdaptObj1() (without type casting) using object reference of AdapterVersion (Parent class)
abstract class AdapterVersion {
public abstract void getMObject();
public abstract void getCObject();
}
public class AdapterVer1 extends AdapterVersion {
#Override
public void getMObject() {
System.out.println("AdapterVer1 Mont");
}
#Override
public void getCObject() {
System.out.println("AdapterVer1 Conf");
}
public void getAdaptObj1() {
}
}
public class AdapterFactory {
public static void main(String []a){
AdapterFactory adapterFactory= new AdapterFactory();
AdapterVersion adpater = adapterFactory.getMyObject("ver1");
adpater.getAdaptObj1(); // Unable to do that
((AdapterVer1)adpater).getAdaptObj1(); // Working but DONT WANT THIS
}
public AdapterVersion getMyObject(String version){
if(version.equals("ver1")){
return new AdapterVer1();
}else{
return new AdapterVer2(); // another declared class
}
}
}
You can't do that. Because at compile time, the compiler checks whether the method you invoked is accessible or visible in the class of the reference you are using or not.
So, in this case, since the reference is of Parent class, the compiler will look for the method declaration in the Parent class first in order to successfully compile the code.
Remember: -
Compiler is worried about the Reference type, and at runtime, the actual object type is considered, to decide which method to actually invoke.
The only option you have is to typecast, in which case, the compiler now looks into the class in which you typecasted the reference. Other option is, you can declare an abstract method with that name in Parent class, but from your question, it seems like you explicitly haven't done that.
You would need to move the method declaration to the abstract class.
Rohit already explained it beautifully. Just to add my 2 cents, you should first check the subclass type and then typecast, for instance:
if(adapter instanceof Adapterver1) {
((AdapterVer1)adpater).getAdaptObj1();
}
This way your code will be safer if it tries to handle a new subclass which doesn't declare such method.
But the question you must ask, if you already know what subclass method to call, why accessing it from superclass reference?

Categories

Resources