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.
Related
I'm studying CS and we have questions about polymorphism that I cant wrap my mind around. Here is an example:
public class AA{
public AA(){
foo();
}
private void foo() {
System.out.print("AA::foo ");
goo();
}
public void goo(){
System.out.print("AA::goo ");
}
}
public class BB extends AA{
public BB(){
foo();
}
public void foo(){
System.out.print("BB:foo ");
}
public void goo(){
System.out.print("BB::goo ");
}
public static void main(String[] args){
// Code goes here
}
}
When in void main i add the line:
AA a = new BB();
it goes first AA constructor prints AA:foo but then goo() sends it to BB's goo, why so?
Simple polymorphism such as "Animal -> cat/spider/dog" is easy to understand but when it comes to this I'm just lost. Can you guys give me any tips how to read this code? What are the rules are?
EDIT: there is no #Override annotation because this is a question from an exam.
Explanation
public class AA {
private void foo() { ... }
^^^^^^^
}
Polymorphism is not applied to private methods. A subclass does not inherit private methods, so they cannot be overridden:
A class C inherits from its direct superclass all concrete methods m (both static and instance) of the superclass for which all of the following are true:
m is a member of the direct superclass of C.
m is public, protected, or declared with package access in the same package as C.
No method declared in C has a signature that is a subsignature of the signature of m.
Java Language Specification - 8.4.8. Inheritance, Overriding, and Hiding
Therefore, the foo() call from the A constructor doesn't invoke BB#foo, it calls AA#foo.
But the goo() call within AA#foo refers to the overridden method BB#goo. Here, with public methods, method overriding and polymorphism were applied.
It's a bit tricky, so I would recommend you put the #Override annotation everywhere it's supposed to be.
public class BB extends AA {
#Override // it doesn't compile - no overriding here
public void foo() { ... }
#Override // it does override
public void goo() { ... }
}
It also might be helpful to detect another problem:
Programmers occasionally overload a method declaration when they mean to override it, leading to subtle problems. The annotation type Override supports early detection of such problems.
If a method declaration in type T is annotated with #Override, but the method does not override from T a method declared in a supertype of T, or is not override-equivalent to a public method of Object, then a compile-time error occurs.
Java Language Specification - 9.6.4.4. #Override
Illustration
If a constructor body does not begin with an explicit constructor invocation and the constructor being declared is not part of the primordial class Object, then the constructor body implicitly begins with a superclass constructor invocation super();, an invocation of the constructor of its direct superclass that takes no arguments.
Java Language Specification - 8.8.7. Constructor Body
To put it simply,
public BB() {
foo();
}
turns into
public BB() {
super();
foo();
}
Keeping super(); in mind, we can make the next illustration:
new BB()
AA() // super(); -> AA constructor
A#foo() // private method call
B#goo() // polymorphic method call
BB() // BB constructor
B#foo() // plain method call
It's explained very well in the official docs:
https://docs.oracle.com/javase/tutorial/java/IandI/super.html
If a constructor does not explicitly invoke a superclass constructor, the Java compiler automatically inserts a call to the no-argument constructor of the superclass. If the super class does not have a no-argument constructor, you will get a compile-time error. Object does have such a constructor, so if Object is the only superclass, there is no problem.
So, the Java compiler is adding super() without args for you.
In fact, if the class you are extending doesn't have a default constructor you will be required to call this constructor with args before.
Otherwise, the reason why AA:goo is not being called is because is override by BB even if it doesn't have the #Override annotation, if you want to see that call you need to use super(); in your b:goo method. In fact, the foo is not override because it private so it's not possible to override it, if you try to add the annotation #Override you'll se you have a compilation failure.
AA::foo() is private so AA::foo() and BB::foo() aren't the same.
new BB()
will call AA::Constructor first, calling AA::foo().
AA::foo() call goo() and since you instantiated BB class it'll be BB::goo().
Please use "override" keyword on method when you want to do something like this
There is also a serious design flaw in the example code: it is calling an overridable method from a constructor. This means that object BB might not be fully initialized at the time that this method is called on it. For example:
public class AA{
public AA(){
foo();
}
private void foo() {
System.out.print("AA::foo ");
goo();
}
public void goo(){
System.out.print("AA::goo ");
}
}
public class BB extends AA{
private Date timestamp;
public BB() {
super();
foo();
timestamp = new Date();
}
public void foo() {
System.out.print("BB:foo ");
}
public void goo() {
// goo() gets called before timestamp is initialized
// causing a NullPointerException
System.out.print("BB::goo " + timestamp.getYear());
}
public static void main(String[] args){
AA obj = new BB();
}
}
Remember this: NEVER CALL AN OVERRIDABLE METHOD FROM A CONSTRUCTOR (even not indirectly as in this example)
Polymorphism is Simple yet Confusing at times when we use different set of names [Which is the case here].
Polymorphism is basically a Parent Child Relationship. Key here is, if you are trying hard to place the names of the classes, use yourself instead i.e. give comment line next to class names as below
public class AA{} //your Parent name
public class BB extends AA{} // yourself i.e. your name
When it comes to the code like this, AA a = new BB(); , decode the code as below:
BB is you, AA is your parent.
new keyword is with YOU(i.e. BB), so a new object of YOU would be created or born. In order to for YOU to born, without your parents(i.e. AA), you cannot exist and so, first they will be born or created (i.e. AA constructor would run). Once your Parents (i.e. AA) are created, then it is time for YOU to born(i.e. BB constructor would run).
In your example,
public AA(){
foo(); -- line A
}
private void foo() {
System.out.print("AA::foo ");
goo(); -- line B
}
public void goo(){
System.out.print("AA::goo "); -- line C
}
As I told earlier, Line A would be called when you say AA a = new BB(); as Line A is in Constructor of AA, Line A calls foo() method and so the control lands in foo(), prints "AA::foo " and executes Line B. Line B calls goo() method and so on it reaches Line C. After Line C is executed, there is nothing left to execute in AA constructor (i.e. Object is created) and so the control flows down to the child Constructor ( As parent is created, it is time for the child to born) and so the child Constructor would be called next.
For Students/Beginners, I strongly recommend to go through Head First Java Edition. It really helps you in laying the Java Foundation Strong.
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.
I am new to Java and I have read threads (here) that it is not possible to instantiate an abstract class. So, I tested it out.
The first test I did is shown below. And it seems like I can actually instantiate an abstract class and in fact, I actually have a new type which refers to the abstract class and the type is actually shared by all subclasses the extends it. This also means polymorhpism applies.
import java.util.*;
abstract class AbstractClass{
public abstract void printname();
}
class Test1 extends AbstractClass{
private String name;
public Test1(String name){
this.name = name;
}
public void printname(){
System.out.println("My name is " + name);
}
}
class Test2 extends AbstractClass{
private String saysomething;
public Test2(String saysomething){
this.saysomething = saysomething;
}
public void printname(){
System.out.println(saysomething);
}
}
class TestingApp{
public static void main(String[] args){
AbstractClass[] abstractclass_list = {new Test1("JEFFFFFF") , new Test2("Hey , say something")};
for(AbstractClass item : abstractclass_list){
item.printname();
}
}
}
Then I did another test but this time, instead of working on abstract class, I decided to create a type which refers to Interface. It seems like I can instantiate an interface as well. I can actually create a type that refers to the interface. This type is shared by all the classes that implements this interface. And polymorphism applies again.
import java.util.*;
interface AbstractInterface{
public void printname();
}
class Test4 implements AbstractInterface{
private String name;
public Test4(String name){
this.name = name;
}
public void printname(){
System.out.println("My name is " + name);
}
}
class Test3 implements AbstractInterface{
private String saysomething;
public Test3(String saysomething){
this.saysomething = saysomething;
}
public void printname(){
System.out.println(saysomething);
}
}
class TestingAbstractInterfaceApp{
public static void main(String[] args){
AbstractInterface[] abstract_list = {new Test4("Helen") , new Test3("Hey , say my name")};
for(AbstractInterface item : abstract_list){
item.printname();
}
}
}
Question:
I am sensing there is something wrong with what I am doing in my code. But I cannot quite explain how come the code still works when theoretically, it is impossible to instantiate an abstract class and interface. Am I actually instantiating an abstract class and an interface in the examples shown above ? Because this seems like exactly what I have done, as I have a new type for the abstract class and interface. Please correct me, if my logic is wrong or if I am using the wrong words.
Update:
SO I guess my misunderstanding is about type. I always thought type can only refer to normal Java classes but not abstract classes and interfaces. How does "type" actually work? Is it creating a reference?
Why do you think you are actually instantiating AbstractClass and AbstractInterface?
new Test1("JEFFFFFF") , new Test2("Hey , say something"), new Test4("Helen") , new Test3("Hey , say my name") are all instantiating concrete classes, not abstract ones.
If you refer to AbstractClass[] abstractclass_list = as proof of instantiating abstract classes, that is wrong. Here, you declare an array whose elements are of type AbstractClass, and Test1 and Test2 are (since they extend AbstractClass).
UPDATE
You could have something like this AbstractClass abs = new Test1("hey"); and what it does is it creates a new instance of class Test1, and references that instance from variable abs. abs's concrete type is Test1, but only methods declared in AbstractClass are visible on it. If you want to call methods of Test1, you would have to cast it first.
AbstractClass abs = new Test1("hey");
abs.printname(); // this is ok, and it calls `printname() implemented in Test1
abs.someTest1Method(); // this is NOT ok, someTest1Method() is not visible to abs
((Test1)abs).someTest1Method(); // this is ok, abs is cast to Test1, but would fail if abs was instantiated as 'abs = new Test2("t2")' (would throw ClassCastException)
You are not instantiating your abstract class or your interface. You are instantiating concrete classes that extend your abstract class (Test1 and Test2) or implement your interface (Test3 and Test4).
It's allowed to assign an instance of a concrete class to a variable whose type is an interface or an abstract class. In fact, it's even encouraged.
You aren't instantiating either an abstract class, nor an interface. You are just using the inherent upcasting ability from subclasses to superclasses.
Ignoring the array, and using just the first object, this would be equivalent to the implicit upcasts:
AbstractClass myObject = new Test1("JEFFFFFF");
and
AbstractInterface myObject = new Test1("JEFFFFFF");
So, in the code:
AbstractClass[] abstractclass_list = {
new Test1("JEFFFFFF") ,
new Test2("Hey , say something")};
You are instantiating objects of the concrete classes Test1 and Test2 - the Array contains references to the underlying (and common) abstract base class.
Similarly, in the second example, you are obtaining an array of interface references.
In short I would like to say that,
Parent(here, Abstract/Iterface) can refer, it's child(here, concrete class).
So here, reference variable can refer it's child class's instance.
Just note this concept in your brain, it will fix all your problem regarding, Dynamic Dispatcher, Inheritance related....!!!
You are not instantiating an abstract class and an interface,
you are instantiating some specific implementations of that abstract class and of that interface.
If you declare a list of AbstractClass or AbstractInterface you can just calls methods declared on your superclass or interface but not these declared on your specific implementations (Test1, Test2, Test3 and Test4).
If Abstract class cannot be instantiated, then how can the variables
access and methods access of the abstract class A even without
extending is achieved in the class check (as you can see in the below
code)
Is the created a an object of abstract class A?
CODE
abstract class A
{
int a=10;
public A()
{
System.out.println("CONSTRUCTOR ONE");
}
public A(String value)
{
System.out.println("CONSTRUCTOR "+value);
}
void add(int sum)
{
System.out.println("THE SUM IS:"+sum);
}
int sub(int a,int b )
{
return(a-b);
}
}
public class check
{
public check()
{
new A("TWO"){};
}
public static void main(String args[])
{
int a,b,sum;
a=10;
b=15;
sum=a+b;
A s = new A() {};
new check();
s.add(sum);
int subb=s.sub(35,55);
System.out.println("THE SUB IS:"+subb);
System.out.println("THE VALUE OF A IS:"+s.a);
}
}
OUTPUT
CONSTRUCTOR ONE
CONSTRUCTOR TWO
THE SUM IS:25
THE SUB IS:-20
THE VALUE OF A IS:10
BUILD SUCCESSFUL (total time: 0 seconds)
The new A() {} call creates an anonymous subclass and instantiates that. Since A does not contain any abstract methods, this works.
You are creating subclass of A with this code -
A s = new A() {};
and here as well -
public check()
{
new A("TWO"){};
}
Whereas, the normal syntax for instantiation is this -
A a = new A();
which would give compilation error if you try to run this code. As such, you don't have any abstract method in your class, and hence a nominal subclass suffices and you get your code executed.
HTH,
- Manish
The normal use case is, you'd write new MyAbstractClass(){ and then implement whatever abstract methods you need to implement (and/or override existing non-abstract methods), and the compiler will infer a non-abstract subclass for you. Since your class doesn't have any abstract methods, it's not necessary to override anything.
A is marked abstract but has no abstract methods so when you do new A() {} you are providing an implementation that has nothing in it thus you are providing a concrete implementation and the class is complete.
Disregarding "visibility" (public, private, package scope, etc)... you generally need a class instance to access class members.
An exception is static classes.
Otherwise, if you have an abstract base class, you'll need to subclass to get an instance.
In your case, however, the class isn't really "abstract" (despite your attempting to label it as such). Simply because there are no abstract members or methods.
You created abstract class A without any abstract method.
Abstract classes cannot be instantiated, but they can be subclassed.
An abstract method is a method that is declared without an implementation.
In the constructor check() you just created anonymous class and call constructor A(String value).
new A("TWO"){};
This is a anonymous subclass .
1. This class create and instantiate at the same time...
2. No name of that class..
3. Because there is no name so it must need a parent .
You can get name by s.getClass().getName(); which return A$1....
A s = new A() {};
on the right side there is a new anonimus class which is inherited from A.A class haven't abstract methods so in your new anonimus class you don't need to override any methods.
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".