class Bank{
float getRateOfInterest(){return 0;}
}
class SBI extends Bank{
float getRateOfInterest(){return 8.4f;}
}
class TestPolymorphism{
public static void main(String args[]){
Bank a = new SBI();
SBI b = new SBI();
a.getRateOfInterest();
b.getRateOfInterest();
}
}
a.getRateOfInterest() and b.getRateOfInterest() both gives same output. So what is the difference between both the statements?
I think 1st is upcasting.
Java methods are all virtual, so the method called depends on the run-time type of the called object, not on the compile-time type of the variable holding the reference.
It's not, if you construct it with new SBI(). It'll always return 8.4f.
All java method is virtual (by design).
They rely on the implementing classes to provide the method implementations.
Here is more information.
- Can you write virtual functions / methods in Java?
- https://en.wikipedia.org/wiki/Virtual_function
Here is an excerpt from wikipedia :-
public class Animal {
public void eat() {
System.out.println("I eat like a generic Animal.");
}
public static void main(String[] args) {
Animal animal=new Wolf ();
animal.eat(); //print "I eat like a wolf!
}
}
class Wolf extends Animal {
#Override
public void eat() {
System.out.println("I eat like a wolf!");
}
}
Virtual functions are resolved 'late'. If the function in question is
'virtual' in the base class, the most-derived class's implementation
of the function is called according to the actual type of the object
referred to, regardless of the declared type of the pointer or
reference. If it is not 'virtual', the method is resolved 'early' and
the function called is selected according to the declared type of the
pointer or reference.
Virtual functions allow a program to call methods that don't
necessarily even exist at the moment the code is compiled.
Related
When a class extends a class, we can use Super-class reference while assigning memory to the subclass object.
I have understood so far is that it is ok to do so, because a subclass inherits the data of its parent class, but it cannot access the members of the subclass because it is the just the reference, and hence does not know of what additions are done by the child class.
My question is when I included method hiding to the above concept, the superclass reference variable started to refer to the child's class function. Why is that ? Why it didnt call it's own method as it is supposed to ?
class A{
void show(){ System.out.print("CLass A. \n"); }
}
class B extends A{
void show(){System.out.print("Class B. \n"); }
}
class Main{
public static void main(String[] args){
A a= new A();
B b= new B();
a.show(); // prints Class A
b.show(); // prints Class B
A a1= new B();
a1.show(); // print Class B. why is this ? it should be Class A as per theory?
}
}
variables and methods are two different things. Variables stick to their types where as methods get executed run time based on the implementation type provided.
Polymorphism. Methods bind dynamically and choosen at run time. If you ovveride them implementation class, they get executed otherwise the implementation from type class gets execute.
When you write
A a1= new B();
Means that please call the implementations from the class B(which is on right side) which are from type A
You have to know about overriding concept in java.
From oracle documentation page regarding overriding:
Overriding and Hiding Methods
Instance Methods
An instance method in a subclass with the same signature (name, plus the number and the type of its parameters) and return type as an instance method in the superclass overrides the superclass's method
The ability of a subclass to override a method allows a class to inherit from a superclass whose behavior is "close enough" and then to modify behavior as needed.
But overriding is different from hiding.
Static Methods
If a subclass defines a static method with the same signature as a static method in the superclass, then the method in the subclass hides the one in the superclass.
The distinction between hiding a static method and overriding an instance method has important implications:
The version of the overridden instance method that gets invoked is the one in the subclass.
The version of the hidden static method that gets invoked depends on whether it is invoked from the superclass or the subclass.
Example to understand:
public class Animal {
public static void testClassMethod() {
System.out.println("The static method in Animal");
}
public void testInstanceMethod() {
System.out.println("The instance method in Animal");
}
}
public class Cat extends Animal {
public static void testClassMethod() {
System.out.println("The static method in Cat");
}
public void testInstanceMethod() {
System.out.println("The instance method in Cat");
}
public static void main(String[] args) {
Cat myCat = new Cat();
Animal myAnimal = myCat;
Animal.testClassMethod();
myAnimal.testInstanceMethod();
}
}
output:
The static method in Animal
The instance method in Cat
It allways calls the method from the most specific class.
Imagine following code:
public class BaseClass {
private int a;
public void noReturnNoParam() {
System.out.println("From Base Class");
}
}
public class ExtendedClass extends BaseClass {
private int b;
#Override
public void noReturnNoParam() {
System.out.println("From Extended Class");
}
}
public class Polymorph {
public static void main(String... args) {
BaseClass bc = new BaseClass();
ExtendedClass ec = new ExtendedClass();
BaseClass bcec = new ExtendedClass();
bc.noReturnNoParam();
ec.noReturnNoParam();
bcec.noReturnNoParam();
}
}
Output is as follows:
From Base Class
From Extended Class
From Extended Class
So how can I achieve that, on calling bcec.noReturnNoParam() the BaseClass` method is called? (and only if the ExtendedClass object is stored in a BaseClass type)?
That's exactly the concept of polymorphism:
BaseClass bcec = new ExtendedClass();
BaseClass is the contract you declared for bcec. It give your compile time information about what you can get from bcec. It tells you that you can call noReturnNoParam method.
ExtendedClass is the actually implementation of bcec. JVM know at runtime that bcec.noReturnNoParam() is invoking the noReturnNoParam in ExtendedClass.
The below statement is similar:
ExtendedClass ec = new ExtendedClass();
ExtendedClass on the left is the contract, tells you what you can get from ec. ExtendedClass on the right is the actual implementation, which is executed at runtime.
ExtendedClass extends BaseClass, so an instance of ExtendedClass is also an instance of BaseClass. But an instance of BaseClass might not be an instance of ExtendedClass. That's why the below cannot compile:
ExtendedClass abc = new BaseClass();
I give you another example to make the concept less abstract.
class Fruit {
void taste() {
System.out.println("delicious!");
}
}
class Apple extends Fruit{
void taste() {
System.out.println("sweet!");
}
}
class Orange extends Fruit{
void taste() {
System.out.println("juicy!");
}
}
class Polymorph {
public static void main(String... args) {
Fruit fruit = new Fruit();
Apple apple = new Apple();
Fruit fruit_apple = new Apple();
Fruit fruit_orange = new Orange();
fruit.taste(); // prints delicious!
apple.taste(); // prints sweet!
fruit_apple.taste(); // prints sweet!
fruit_orange.taste(); // prints juicy!
}
}
Orange and Apple are both Fruit. Fruit/Orange/Apple all have tastes, and Orange and Apple have their own tastes. You say an apple is a kind of fruit, an orange is also a kind of fruit, but you can't say a fruit is an apple.
This is called Dynamic Polymorphism \ Dynamic method binding in which at runtime,
JVM call method of object type, NOT reference type. In this case object type is ExtendedClass, hence its calling method from that class.
And you cant avoid it.
The issue you are having is with static vs dynamic binding.
With dynamic binding, methods will be dynamically called at run-time. Here's a good little article to read if you need clarification.
To my knowledge, you wont be able to strictly call the base method the way your classes are currently designed. Only from the derived class' method can you call the base class' since you are overriding it.
So, even though you are declaring it for the compiler as the base class, the object is really an object of the derived class, and as such, its methods will be called during run-time.
This is demonstration of one of the base principles OOP. It is called polymorphism.
Independent of how your class(BaseClass in your example) looks like it will work as it class which was used for initialisation(ExtendedClass).
This is not what intended from Polymorphism. Any way you can make your extended class to call its super class implementation in its method like
#Override
public void noReturnNoParam() {
super.noReturnNoParam(); // here base class implementation will be run
System.out.println("From Extended Class");
}
But you cannot make it to call only base class implementation.
The Java virtual machine (JVM) calls the appropriate method for the
object that is referred to in each variable. It does not call the
method that is defined by the variable's type. This behavior is
referred to as virtual method invocation and demonstrates an aspect of
the important polymorphism features in the Java language.
If Method calls are dynamically binded then why the Compiler complains
The method run() is undefined for the type B
Why is compiler checking for the presence of method run in Class b
Here is the code
import java.lang.*;
public class Program
{
public static void main(String [] args)
{
B a = new A();
a.run();//compiler complains at this line.
a.p(10);
a.p(10.0);
}
}
class B {
public void p(int i)
{
System.out.println(i*2);
}
}
class A extends B{
public void p(int i)
{
System.out.println(i);
}
public void run(){
}
}
Java is by design a statically typed language, meaning that the compiler must know and be able to guarantee that an implementation of that method exists in every concrete object. (Maxim Shoustin's answer very nicely demonstrates the reason behind this design decision with an example.)
If the compiler were to assume without any guarantees that an unknown object will happen to have a specific method, it would make Java a duck typed language. This could have its own advantages, but it wasn't in accordance with the design goals of Java.
In practice, in statically typed languages, virtual (meaning non-final) methods (such as your run() method) are resolved dynamically but the strategy used to resolve them is still written at compile time. That strategy may, for example, involve reading the correct offset of the vTable (a table containing the addresses of the actual implementations of the virtual methods of that object), in many implementations of polymorphism - leveraging the type safety of the language to gain some performance during the dynamic dispatch.
The method run() is undefined for the type B
The error is self explanatory. The type B doesn't have a method called .run()
B a = new A() means that your variable a is of type B and that is all the system knows about the variable a.
If you did Object s = new String() and then did s.toLowerCase() it would fail as well, because the variable s is of type Object not of type String.
whatever type your variable is, is the only behaviors that you can call on that type.
Its easy to show:
Let me change your code a bit:
B = Animal
A = Cow
after replace:
public class Program
{
public static void main(String [] args)
{
Animal a = new Cow();
a.sayMooo();//compiler complains at this line. You try to animal to say "moo"?
a.speed(10);
a.speed(10.0);
}
}
class Animal {
public void speed(int i)
{
System.out.println(i*2);
}
}
class Cow extends Animal{
public void p(int i)
{
System.out.println(i);
}
public void sayMooo(){
}
}
Not all animals are Cows
and sure
Not all animals say "mooo"
but
all Cows are animals
I'm confused about what it means to cast objects in Java.
Say you have...
Superclass variable = new Subclass object();
(Superclass variable).method();
What is happening here? Does the variable type change, or is it the object within the variable that changes? Very confused.
Have a look at this sample:
public class A {
//statements
}
public class B extends A {
public void foo() { }
}
A a=new B();
//To execute **foo()** method.
((B)a).foo();
Say you have a superclass Fruit and the subclass Banana and you have a method addBananaToBasket()
The method will not accept grapes for example so you want to make sure that you're adding a banana to the basket.
So:
Fruit myFruit = new Banana();
((Banana)myFruit).addBananaToBasket(); ⇐ This is called casting
The example you are referring to is called Upcasting in java.
It creates a subclass object with a super class variable pointing to it.
The variable does not change, it is still the variable of the super class but it is pointing to the object of subclass.
For example lets say you have two classes Machine and Camera ; Camera is a subclass of Machine
class Machine{
public void start(){
System.out.println("Machine Started");
}
}
class Camera extends Machine{
public void start(){
System.out.println("Camera Started");
}
public void snap(){
System.out.println("Photo taken");
}
}
Machine machine1 = new Camera();
machine1.start();
If you execute the above statements it will create an instance of Camera class with a reference of Machine class pointing to it.So, now the output will be "Camera Started"
The variable is still a reference of Machine class. If you attempt machine1.snap(); the code will not compile
The takeaway here is all Cameras are Machines since Camera is a subclass of Machine but all Machines are not Cameras. So you can create an object of subclass and point it to a super class refrence but you cannot ask the super class reference to do all the functions of a subclass object( In our example machine1.snap() wont compile). The superclass reference has access to only the functions known to the superclass (In our example machine1.start()). You can not ask a machine reference to take a snap. :)
Sometimes you will like to receive as argument a Parent reference and inside you probably want to do something specific of a child.
abstract class Animal{
public abstract void move();
}
class Shark extends Animal{
public void move(){
swim();
}
public void swim(){}
public void bite(){}
}
class Dog extends Animal{
public void move(){
run();
}
public void run(){}
public void bark(){}
}
...
void somethingSpecific(Animal animal){
// Here you don't know and may don't care which animal enters
animal.move(); // You can call parent methods but you can't call bark or bite.
if(animal instanceof Shark){
Shark shark = (Shark)animal;
shark.bite(); // Now you can call bite!
}
//doSomethingSharky(animal); // You cannot call this method.
}
...
In above's method you can pass either Shark or Dog, but what if you have something like this:
void doSomethingSharky(Shark shark){
//Here you cannot receive an Animal reference
}
That method can only be called by passing shark references
So if you have an Animal (and it is deeply a Shark) you can call it like this:
Animal animal...
doSomethingSharky((Shark) animal)
Bottom line, you can use Parent references and it is usually better when you don't care about the implementation of the parent and use casting to use the Child as an specific object, it will be exactly the same object, but your reference know it, if you don't cast it, your reference will point to the same object but cannot be sure what kind of Animal would it be, therefore will only allow you to call known methods.
Superclass variable = new subclass object(); This just creates an object of type subclass, but assigns it to the type superclass. All the subclasses' data is created etc, but the variable cannot access the subclasses data/functions. In other words, you cannot call any methods or access data specific to the subclass, you can only access the superclasses stuff.
However, you can cast Superclassvariable to the Subclass and use its methods/data.
Lets say you have Class A as superclass and Class B subclass of A.
public class A {
public void printFromA(){
System.out.println("Inside A");
}
}
public class B extends A {
public void printFromB(){
System.out.println("Inside B");
}
}
public class MainClass {
public static void main(String []args){
A a = new B();
a.printFromA(); //this can be called without typecasting
((B)a).printFromB(); //the method printFromB needs to be typecast
}
}
In this example your superclass variable is telling the subclass object to implement the method of the superclass. This is the case of the java object type casting. Here the method() function is originally the method of the superclass but the superclass variable cannot access the other methods of the subclass object that are not present in the superclass.
For example you have Animal superclass and Cat subclass.Say your subclass has speak(); method.
class Animal{
public void walk(){
}
}
class Cat extends Animal{
#Override
public void walk(){
}
public void speak(){
}
public void main(String args[]){
Animal a=new Cat();
//a.speak(); Compile Error
// If you use speak method for "a" reference variable you should downcast. Like this:
((Cat)a).speak();
}
}
in some cases we can’t provide guarantee for the type of elements or objects present inside our collection or wise,
at the time of retrieval compulsory we should perform type casting otherwise we will get compile time error.
Arrays are always type safe that is we can provide the guarantee for the type of elements present inside array.
to achieve type safety we have to use typecasting.
Casting is necessary to tell that you are calling a child and not a parent method. So it's ever downward. However if the method is already defined in the parent class and overriden in the child class, you don't any cast. Here an example:
class Parent{
void method(){ System.out.print("this is the parent"); }
}
class Child extends Parent{
#override
void method(){ System.out.print("this is the child"); }
}
...
Parent o = new Child();
o.method();
((Child)o).method();
The two method call will both print : "this is the child".
Is it possible to write virtual methods in Java, as one would do in C++?
Or, is there a proper Java approach which you can implement that produces similar behavior? Could I please have some examples?
From wikipedia
In Java, all non-static methods are by
default "virtual functions." Only
methods marked with the keyword final,
which cannot be overridden, along with
private methods, which are not
inherited, are non-virtual.
Can you write virtual functions in Java?
Yes. In fact, all instance methods in Java are virtual by default. Only certain methods are not virtual:
Class methods (because typically each instance holds information like a pointer to a vtable about its specific methods, but no instance is available here).
Private instance methods (because no other class can access the method, the calling instance has always the type of the defining class itself and is therefore unambiguously known at compile time).
Here are some examples:
"Normal" virtual functions
The following example is from an old version of the wikipedia page mentioned in another answer.
import java.util.*;
public class Animal
{
public void eat()
{
System.out.println("I eat like a generic Animal.");
}
public static void main(String[] args)
{
List<Animal> animals = new LinkedList<Animal>();
animals.add(new Animal());
animals.add(new Fish());
animals.add(new Goldfish());
animals.add(new OtherAnimal());
for (Animal currentAnimal : animals)
{
currentAnimal.eat();
}
}
}
class Fish extends Animal
{
#Override
public void eat()
{
System.out.println("I eat like a fish!");
}
}
class Goldfish extends Fish
{
#Override
public void eat()
{
System.out.println("I eat like a goldfish!");
}
}
class OtherAnimal extends Animal {}
Output:
I eat like a generic Animal.
I eat like a fish!
I eat like a goldfish!
I eat like a generic Animal.
Example with virtual functions with interfaces
Java interface methods are all virtual. They must be virtual because they rely on the implementing classes to provide the method implementations. The code to execute will only be selected at run time.
For example:
interface Bicycle { //the function applyBrakes() is virtual because
void applyBrakes(); //functions in interfaces are designed to be
} //overridden.
class ACMEBicycle implements Bicycle {
public void applyBrakes(){ //Here we implement applyBrakes()
System.out.println("Brakes applied"); //function
}
}
Example with virtual functions with abstract classes.
Similar to interfaces Abstract classes must contain virtual methods because they rely on the extending classes' implementation. For Example:
abstract class Dog {
final void bark() { //bark() is not virtual because it is
System.out.println("woof"); //final and if you tried to override it
} //you would get a compile time error.
abstract void jump(); //jump() is a "pure" virtual function
}
class MyDog extends Dog{
void jump(){
System.out.println("boing"); //here jump() is being overridden
}
}
public class Runner {
public static void main(String[] args) {
Dog dog = new MyDog(); // Create a MyDog and assign to plain Dog variable
dog.jump(); // calling the virtual function.
// MyDog.jump() will be executed
// although the variable is just a plain Dog.
}
}
All functions in Java are virtual by default.
You have to go out of your way to write non-virtual functions by adding the "final" keyword.
This is the opposite of the C++/C# default. Class functions are non-virtual by default; you make them so by adding the "virtual" modifier.
All non-private instance methods are virtual by default in Java.
In C++, private methods can be virtual. This can be exploited for the non-virtual-interface (NVI) idiom. In Java, you'd need to make the NVI overridable methods protected.
From the Java Language Specification, v3:
8.4.8.1 Overriding (by Instance Methods) An instance method m1
declared in a class C overrides
another instance method, m2, declared
in class A iff all of the following
are true:
C is a subclass of A.
The signature of m1 is a subsignature (§8.4.2) of the signature
of m2.
Either
* m2 is public, protected or declared with default access in the
same package as C, or
* m1 overrides a method m3, m3 distinct from m1, m3 distinct from
m2, such that m3 overrides m2.
Yes, you can write virtual "functions" in Java.
In Java, all public (non-private) variables & functions are Virtual by default.
Moreover variables & functions using keyword final are not virtual.