YuWebdesign



OOPS (Object Oriented Programming) concept in Java

By YuwebDesign

Object Oriented Programming features in Java

four pillars of oops

  1. Abstraction deals with (conceptual, abstract) ideas rather than (specific, concrete) events.
    Abstraction hides complexity by giving you a more abstract picture.
  2. Abstraction is the methodology of hiding the implementation details from the user and revealing only the functionality to them.
  3. Abstraction hides details at the design level: it lets you focus on what the object does instead of how it does it.

E.g., vehicle can move.
User won’t know how (if it will drive, or fly or sell). The most essential thing is the ability to move without focusing on details of how exactly will the spatial position of the Vehicle object will be changed.

There are different levels of Abstraction.

Abstraction can be achieved in two ways:

  1. Abstract Classes (0-100% of abstraction can be achieved)
  2. Interfaces (100% of abstraction can be achieved)

As the level of Abstraction increases, things start getting simpler and simpler because the details are left out.

It is a good practice that classes should interact with other classes with the same or higher level of abstraction.

In Java, we use Abstract Class and Interface to achieve Abstraction.

Java OOPs Concepts Abstract Class vs Interface

Abstract Class Interface
Code Can provide complete, default code
and/or just the details that have to be overridden
Cannot provide any code at all, just the signature
Abstract Class contains instance variables. The interface contains only constants.
Methods Contains Abstract methods as well as Non-Abstract methods. All methods of an Interface are abstract.
Inheritance A class may extend only one abstract class A Class may implement several interfaces
Subclass Method Implementation The class which extends the Abstract class shouldn’t require implementing all the methods, only Abstract methods need to be implemented in the concrete sub-class. Classes which implement the interface should provide the implementation for all the methods.
Adding new Method If we add a new method to an abstract class then we have the option of providing default implementation and therefore all the existing code might work properly If we add a new method to an Interface then we have to track down all the implementations of the interface and define implementation for the new method
Constructor Can contain constructors.
Abstract classes have a default constructor and it is called whenever the concrete subclass is instantiated.
Cannot contain constructors.
Cannot be instantiated.
Performance Fast Slow as it needs to find the corresponding method in the actual class

Java OOPs Concepts Encapsulation

  1. Encapsulation – in Java is a mechanism of binding/wrapping up the code(methods) and data(variables) together into a single unit(capsule).
  2. Encapsulation hides details from outside world at the implementation level:
    internal working is hidden and can be changed later without impacting outside clients.

E.g., User should be able to login to their bank online with their user_id and password.
After entering user_id, password they expect to login,
what happens when they press login, how the input data is sent to the server,
and how it gets verified is all abstracted away from the user.

Because of Encapsulation, you can change the internal implementation of the login with ease without impacting clients who are using this feature.

  1. Code maintainability.
  2. Flexibility: implementation details of the class can be changed
    without affecting the classes that are using it.
  3. Increased security of data: protects the code from others.
    The data is hidden from the outer world and can be accessed only via current class methods.
    This helps in protecting the data from any unnecessary modification.
  4. Better control of class attributes and methods.
    Class variables can be made read-only (if you omit the set method),
    or write-only (if you omit the get method)

How to

  1. Declare the instance variables as private
    (accessible only within the same class,
    an outside class has no direct access to it).

    You can only set and get values of these variables
    through the methods of the class.

  2. Have getter and setter methods in the class
    to set and get the values of the variables.
    This will force others to call the setters rather than access the data directly.

Private variables can be accessed with public getter and setter methods.

The get method returns the variable value, and the set method sets the value.

Syntax for both is that they start with either get or set, followed by the name of the variable, with the first letter in upper case:

public class Person {
  private String name; // private = restricted access

  // Getter
  public String getName() {
    return name;
  }

  // Setter
  public void setName(String newName) {
    this.name = newName;
  }
}
  public static void main(String[] args) {
    Person myObj = new Person();

    myObj.name = "John";  // error
    System.out.println(myObj.name); // error  

    myObj.setName("John"); // Set the value of the name variable to "John"
    System.out.println(myObj.getName()); //John
}

Inheritance: process by which one class acquires all the properties and behaviors of another class.

  1. New classes are built upon existing classes (by reusing their code).
  2. The parent class is called the base class or super class.
  3. The child class is called the derived class or sub class.
  4. The child class extends the base class
    Extends keyword indicates that a new class derives from an existing class.
    The meaning of “extends” is to increase the functionality.
  5. The child class can reuse (inherits) methods and fields of the parent class.
  6. The child class can add new methods and fields to define only those features that are unique to it
  7. Inheritance is applicable for public and protected members only. Private members can’t be inherited.
Syntax of Java Inheritance
class Subclass extends Superclass  
{  
   //methods and fields  
}  

The keyword super in Java is a reference variable that refers the immediate parent class object.


With creation of the instance of subclass,
an instance of parent class is created implicitly
which is referred by super reference variable.

Usage of Java Keyword super
  1. to refer immediate parent class instance variable.


    If parent class and child class have same fields, property of the child class is used by default.
    The keyword super is used for accessing the parent property.


    E.g, for printing the common property color of the parent class Animal
    we need to use the keyword super,
    or color of current class will be used by default.

    class Animal{  
    String color="pink";  
    }  
    class Cat extends Animal{  
    String color="striped";  
    void printColor(){  
    System.out.println(color);//prints color of Cat class  
    System.out.println(super.color);//prints color of Animal class  
    }  
    }  
    class InstanceVariableSuper{  
    public static void main(String args[]){  
    Cat dog = new Cat();  
    dog.printColor();  
    }} 
    

    Output:

    striped
    pink
    
  2. to invoke immediate parent class method.


    It should be used if subclass contains the same method as parent class.
    In other words, it is used if method is overridden.

    class Animal{  
    void eat(){System.out.println("eating...");}  
    }  
    class Cat extends Animal{  
    void eat(){System.out.println("eating mouse");}  
    void purr(){System.out.println("purring");}  
    void sleep(){  
    super.eat();  
    purr();  
    }  
    }  
    class OverridenMethodSuper{  
    public static void main(String args[]){  
    Cat cat = new Cat();  
    cat.sleep();  
    }}  
    

    Output:

    eating...
    purring
    
  3. super() invokes immediate parent class constructor.
    class Animal{  
    Animal(){System.out.println("animal is created");}  
    } 
     
    class Cat extends Animal{  
    Cat(){  
    super();  
    System.out.println("cat is created");  
    }}
      
    class parentConstructorSuper{  
    public static void main(String args[]){  
    Cat cat = new Cat();  
    }}  
    

    Output:

    animal is created
    cat is created
    

IS-A relationship (Inheritance)

Inheritance represents the IS-A relationship which is also known as a parent-child relationship.

HAS-A relationship (Aggregation)
  1. If a class has an entity reference, it is known as aggregation.
  2. Relationship where one object contains other objects as a part of its state.
  3. Aggregation represents a HAS-A relationship.
  4. Aggregation represents the weak relationship between objects.

Benefits of Aggregation

  1. Aggregation is used for code reusability.
  2. Code reusability is best achieved by aggregation when there is no IS-A relationship.

Spouse.java

public class Spouse {  
String firstName, middleName, lastName;  
  
public Address(String city, String state, String country) {  
    this.firstName = firstName;  
    this.middleName = middleName;  
    this.lastName = lastName;  
} }  

Citizen.java

class Citizen{  
int ssn;  
String name;  
Spouse spouse;//Spouse is a class  

public Citizen(int ssn, String name, Spouse spouse){  
    this.ssn = ssn;  
    this.name = name;  
    this.spouse = spouse;  
}

void display(){  
System.out.println(ssn+" "+name);  
System.out.println(spouse.firstName+" "+spouse.middleName+" "+spouse.lastName);  
}  

public static void main(String[] args){  
Spouse spouse1 = new Spouse("Thais","Venera","Roman");  
Spouse spouse2 = new Spouse("Esphir","Ishtar","Greek");  
  
Citizen citizen1 = new Citizen(111,"Jupiter Roman", spouse1);  
Citizen citizen2 = new Citizen(777,"Apollo Greek", spouse2);  
      
citizen1.display();  
citizen2.display();  
}}  

Output:

111 Jupiter Roman
Thais  Venera Roman

777 Apollo Greek
Esphir Ishtar Greek

Citizen has an entity reference spouse, so relationship is Citizen HAS-A spouse.

IS-A relationship (Inheritance) vs HAS-A relationship (Aggregation)

Inheritance should be used only if the relationship IS-A is maintained throughout the lifetime of the objects involved; otherwise, aggregation is the best choice.

Association is a relationship between two separate classes which establishes through their Objects.
In simple words, Association represents the relationship between the objects.

In OOPs, an Object communicates to other Object to use functionality and services provided by that object.

  • Objects have their own lifecycle and there is no owner.
  • One object can be associated with one object or many objects.
    The relationships can be one to one, one to many, many to one and many to many.
  • Association can be uni-directional (department can have students but vice versa is not possible) or bi-directional.
Four types of association between the objects:
  1. One to One (e.g. husband and wife)
  2. One to Many (e.g., one mother and many children)
  3. Many to One (e.g., many children and one father)
  4. Many to Many (e.g., many cousins to many cousins)

E.g., Teacher and Student.
Multiple students can associate with a single teacher
and a single student can associate with multiple teachers
but there is no ownership between the objects and both have their own lifecycle.

An aggregation is a special form of Association where:

  • It represents Has-A relationship
  • all objects have their own lifecycle but there is ownership
    and child object can not belong to another parent object.
  • It is a unidirectional association i.e. a one way relationship.
    E.g., department can have students but vice versa is not possible and thus unidirectional in nature.
  • In Aggregation, both entities can survive individually
    which means ending one entity will not effect the other entity.
  • E.g., University has Departments.
    University class references object(s) of the Department class = it is associated with Department class through its Object(s).
    Departments have Students.
    Department class references object(s) of Student class = it is associated with Student class through its Object(s).

    When do we use Aggregation?
    Code reuse is best achieved by aggregation.

    Composition is a specialized restricted strong form of Aggregation in which two entities are highly dependent on each other.

    1. It represents part-of relationship.
    2. In composition, both the entities are dependent on each other.
    3. We can call this as a “death” relationship: when there is a composition between two entities, the composed object cannot exist without the other entity.

    E.g., Human – Heart
    1) Human cannot survive without Heart.
    2) Heart alone does not have any significance.
    3) When human created, heart is created and human dies, heart also dies.
    4) Human – Heart has one-to-one mapping, also heart is not shareable with other human.

    E.g., House – Rooms
    House can contain multiple rooms.
    There is no independent life of room.
    Any room can not belongs to two different houses.
    If we delete the house, room will automatically delete.

    Aggregation Composition
    Dependency Child can exist independently of Parent.
    An object borrowed from someone else.

    E.g., University-Department-Student: delete Department and Student still exist in the University.

    Object lifetime depends on its owner.
    The child cannot exist independent of the parent.
    Contained object is composed inside containing object,
    when the containing object dies, the memory for contained object is also reclaimed.

    E.g.: Human Heart, Heart dies with Human.

    Type of Relationship “has-a” relation. “part-of” relation
    Type of Association Weak Association Strong Association

    1. Association (has-a)
      Association –> A has-a B object (as a member variable)
      An association almost always implies that one object has the other object as a field/property/attribute (terminology differs).

      It means there is almost always a link between objects (they are associated).

      Order object has a Customer object

      public class Order {
          private Customer customer
      }
      
    2. Dependency (references)

      Dependency –> A references B (as a method parameter or return type)

      A dependency typically (but not always) implies that an object accepts another object as a method parameter, instantiates, or uses another object.

      It means there is no conceptual link between two objects.
      e.g. EnrollmentService object references Student & Course objects (as method parameters or return types)

      public class EnrollmentService {
          public void enroll(Student s, Course c){}
      }
      
      public class A {
          private C c;
          public void myMethod(B b) {
              b.callMethod();
          }
      }
      
    3. Aggregation (has-a + whole-part)
      Special kind of association where there is whole-part relation between two objects. they might live without each other though.

      public class PlayList{
          private List songs;
      }
      

      Note: the trickiest part is to distinguish aggregation from normal association. Honestly, I think this is open to different interpretations.

    4. Composition (has-a + whole-part + ownership)
      Special kind of aggregation. An Apartment is composed of some Rooms. A Room cannot exist without an Apartment. when an apartment is deleted, all associated rooms are deleted as well.

      public class Apartment{
          private Room bedroom;
          public Apartment() {
             bedroom = new Room();
          }
      }
      

    • Method Overriding (so that Runtime Polymorphism can be achieved).
    • Code Reusability.

    Six Types of Inheritance are supported in OOPs (1S2H3M)
    1. Single Inheritance
      a single class extends another class (A->B).
      Supported in Java.

      OOPs Inheritance Types: Single Inheritance

    2. Multi-level inheritance
      • Class extends the child class of the base class (A->B->C).
      • Supported in Java.

      OOPs Inheritance Types: Multilevel Inheritance

    3. Hierarchical inheritance
      • More than one classes extends the same class.
      • One Parent has many Children who also may have several Children.

        e.g., Both class B and Class C extend class A (A->B and A->C).

      • Supported in Java.

      OOPs Inheritance Types: Hierarchical Inheritance

    4. Multiple Inheritance
      • one class extends more than one classes,
        a child class has two parent classes (A->C and B->C).
      • Java doesn’t support multiple inheritance and renders a compile-time error if you inherit 2 classes.
      • For Java supporting Multiple Inheritance means managing Child class dependency of more than one Parent.

        The problem with multiple inheritance is that if multiple parent classes have the same method name,
        then at runtime it becomes difficult for the compiler to decide which parent method to execute from the child class.

        The problem is commonly referred to as Diamond Problem.

      • Multiple Inheritance is very rarely used in software projects.
      • It often leads to problems in the hierarchy and results in unwanted complexity when further extending the class.
      • However, Multiple Inheritance in Java can be achieved using Interfaces.

      OOPs Inheritance Types: Multiple Inheritance

    5. Multipath inheritance
    6. a child class has the same base class with its parents (A->B->D, A->C->D, A->D).

      OOPs Inheritance Types: Multipath Inheritance

    7. Hybrid Inheritance
      a combination of more than one inheritance types.

      E.g., Hybrid Inheritance as the combination of both Single and Multiple Inheritance is not directly supported in Java, but can be achieved through interface.
      OOPs Inheritance Types: Hybrid Inheritance

    Only One Superclass

    Except Object class, which has no superclass, every class has one and only one direct superclass (single inheritance).

    A superclass can have any number of subclasses.
    But a subclass can have only one superclass.

    This is because Java does not support multiple inheritance with classes.

    Although with interfaces, multiple inheritance can be achieved in Java.

    Default Superclass

    In the absence of any other explicit superclass, every class is implicitly a subclass of Object class.

    Inheriting Constructors

    A subclass inherits all the members (fields, methods, and nested classes) from its superclass.

    Constructors are not members, so they are not inherited by subclasses,
    but the constructor of the superclass can be invoked from the subclass.

    Private member inheritance

    A subclass does not inherit the private members of its parent class.
    However, if the superclass has public or protected methods(like getters and setters) for accessing its private fields, these can also be used by the subclass.

    In sub-classes we can inherit members as is, replace them, hide them, or supplement them with new members:

    • The inherited fields can be used directly, just like any other fields.
    • We can declare new fields in the subclass that are not in the superclass.
    • The inherited methods can be used directly as they are.
    • We can write a new instance method in the subclass that has the same signature as the one in the superclass, thus overriding it (as in example above, toString() method is overridden).
    • We can write a new static method in the subclass that has the same signature as the one in the superclass, thus hiding it.
    • We can declare new methods in the subclass that are not in the superclass.
    • We can write a subclass constructor that invokes the constructor of the superclass, either implicitly or by using the keyword super.

    Polymorphism means “many forms”, it is based on on inheritance and occurs when many classes are related to each other by inheritance.

    Inheritance lets us inherit attributes and methods from another class.
    Polymorphism uses those methods to perform a single action in different ways.

    For example, lets say we have a class Animal that has a method animalSound(),
    here we cannot give implementation to this method as we do not know
    which class would extend Animal class.
    So, we make this method abstract like this:

    public abstract class Animal{
       ...
       public abstract void animalSound();
    }

    Animal class Lion that extends Animal class
    can provide implementation details.

    public class Lion extends Animal{
    ...
        @Override
        public void animalSound(){
            System.out.println("Roar");
        }
    }

    Read more about Java Polymorphism on Oracle website >>>

    In Computer Science, there are the following types of polymorphism:

    1. Ad-hoc polymorphism, also called Static Polymorphism or Compile-time Polymorphism or Method Overloading

      allows methods having same name to act differently for different types.

      the compiler (or the runtime system, depending on whether overloading resolution is static or dynamic)
      chooses an appropriate implementation for each application of the function,
      based on the types of the arguments.

      E.g., the + operator adds two integers and concatenates two strings.

      If you overload a static method in Java, it is the example of compile time polymorphism.

    2. Inclusion Polymorphism, also called Subtyping or Dynamic Polymorphism or Run-time Polymorphism or Dynamic Method Dispatch or Method Overriding

      A call to an overridden method is resolved at run-time rather than compile-time.

      It is the ability to use derived classes through base class pointers and references.

      The address of the method is not located by the Compiler at compile-time,
      rather, the right pointer from the virtual table is dereferenced to invoke the method at run-time.

      The concept of Virtual Function, also known as Dynamic Linkage, is employed to achieve Inclusion Polymorphism.
      The usage of Virtual Function allows the selection of that function which is to be invoked based on the kind of object for which it is called.

    3. Coersion Polymorphism, also called Casting
      Coersion Polymorphism occurs when an object or primitive is cast into some other type.

      It could be either Implicit or Explicit.

      Implicit casting happens as a responsibility of Compiler itself.
      E.g., float f=100 (integer implicitly gets promoted to float)

      Read more about Type Casting in Java>>>

    4. Parametric polymorphism also called Early Binding
      Parametric Polymorphism opens a way to use the same piece of code for different types.

      a method or a data type can be written generically
      so that it can handle values identically
      without depending on their type.

      It uses variables in place of actual types,
      and then instantiates with particular types as needed.

      Parametric definitions are uniform: all of their instances behave the same.

      Parametric polymorphism in Java generally refers to Generics/Templates.
      Using Templates, the same function can be parameterized with different types of data,
      but this needs to be decided at compile-time itself, and hence, this polymorphism is named so.

      template  
      temp greater(temp a, temp b) { 
          if (a > b) 
              return a; 
          else
              return b; 
      

      This program can find greater of two Integers or two Strings.

      If we wish to achieve such polymorphism for pointers, it turns into Ad-hoc Polymorphism.

    Static Polymorphism or Compile-time Polymorphism or Method Overloading
    1. Method Overloading: class has multiple methods having same name but different in parameters.
    2. Advantage of method overloading: having the same name of the methods increases the readability of the program.
    3. Compile-time Polymorphism: overloading of a a static method in Java.
    Two ways to overload the method in Java
    1. Changing number of arguments
      class AddNumbers{  
      static int add(int a,int b){return a+b;}  
      static int add(int a,int b,int c){return a+b+c;}  
      }  
      class OverloadingArgumentQuantity{  
      public static void main(String[] args){  
      System.out.println(AddNumbers.add(1,1));  
      System.out.println(AddNumbers.add(1,1,1));  
      }}  
      

      Output:

      2
      3
      
      • first add() method performs addition of two numbers
      • second add method performs addition of three numbers.
      • static methods provide no need to create instance for calling methods.
    2. Changing the data type of arguments
      class AddNumbers{  
      static int add(int a, int b){return a+b;}  
      static double add(double a, double b){return a+b;}  
      }  
      class OverloadingArgumentDatatype{  
      public static void main(String[] args){  
      System.out.println(AddNumbers.add(1,1));  
      System.out.println(AddNumbers.add(1.1,1.2)); 
      }} 
      

      Output:

      2
      2.3
      

    Method Overloading by changing the return type of the method – not possible in Java
    1. In java, Method Overloading is not possible by changing the return type of the method because of ambiguity.
    2. Compile Time Error is better than Run Time Error. So, java compiler renders compiler time error if you declare the same method having same parameters.
    class AddNumbers{  
    static int add(int a, int b){return a+b;}  
    static double add(int a, int b){return a+b;}  
    }  
    class OverloadingMethodDatatype{  
    public static void main(String[] args){  
    System.out.println(AddNumbers.add(1, 1));////ambiguity  
    }} 
    

    Output:

    Compile Time Error: method add(int,int) is already defined in class AddNumbers
    

    Java can not determine which sum() method should be called.

    Overloading Java main() Method
    1. You can have any number of main methods in a class by method overloading.
    2. But JVM calls main() method which receives string array as arguments only.
    class OverloadingMainMethod{  
    public static void main(String[] args){System.out.println("main with String[]");}  
    public static void main(String args){System.out.println("main with String");}  
    public static void main(){System.out.println("main without args");}  
    }  
    

    Output:

    main with String[]
    

    Method Overloading and Type Casting

    One type is promoted to another implicitly if no matching datatype is found.
    Read more about Java Type Casting >>>

    Example of Method Overloading with Type Promotion if matching found
    If there are matching type arguments in the method, type promotion is not performed.

    class OverloadingWithTypeCasting{  
      void sum(int a,int b){System.out.println("int arg method invoked");}  
      void sum(long a,long b){System.out.println("long arg method invoked");}  
      
      public static void main(String args[]){  
      OverloadingWithTypeCasting obj = new OverloadingWithTypeCasting();  
      obj.sum(20,20);//now int arg sum() method gets invoked  
      } }  
    

    Output:

    int arg method invoked
    

    Method Overloading with Type Promotion in case of ambiguity

    1. If there are no matching type arguments in the method, and each method promotes similar number of arguments, there will be ambiguity.
    2. One type is not de-promoted implicitly for example double cannot be depromoted to any type implicitly.
    class OverloadingWithTypeCastingAmbiguity{  
      void sum(int a,long b){System.out.println("a method invoked");}  
      void sum(long a,int b){System.out.println("b method invoked");}  
      
      public static void main(String args[]){  
      OverloadingWithTypeCastingAmbiguity obj = new OverloadingWithTypeCastingAmbiguity();  
      obj.sum(20,20); //ambiguity  
    }}  
    

    Output:

    Compile Time Error
    

    Dynamic/Run-time Polymorphism or Dynamic Method Dispatch or Method Overriding
    1. Rule 1: There must be an IS-A relationship (inheritance).
    2. Rule 2: A subclass (child class) must have the same method name as the parent class (superclass).
    3. Method overriding is used by the child class to provide the specific implementation of the method that has been declared by a parent class.
    4. Rule 3: The child method must have the same parameters as the parent methods.
    5. Method overriding is used for runtime polymorphism: a call to an overridden method is resolved at run-time rather than compile-time.
    6. An overridden method is called through the reference variable of a superclass.
    7. The determination of the method to be called is based on the object being referred to by the reference variable.
    Java Runtime Polymorphism Examples

    Java Runtime Polymorphism Example: Shape

    class Shape{  
    void draw(){System.out.println("drawing...");}  
    }  
    class Square extends Shape{  
    void draw(){System.out.println("drawing square");}  
    }  
    class Circle extends Shape{  
    void draw(){System.out.println("drawing circle");}  
    }  
    class Triangle extends Shape{  
    void draw(){System.out.println("drawing triangle");}  
    }  
    class TestPolymorphism2{  
    public static void main(String args[]){  
    Shape s;  
    s=new Rectangle();  
    s.draw();  
    s=new Circle();  
    s.draw();  
    s=new Triangle();  
    s.draw();  
    } } 
    

    Output:

    drawing square
    drawing circle
    drawing triangle
    

    Java Runtime Polymorphism Example: Animal

    class Animal{  
    void eat(){System.out.println("eating...");}  
    }  
    class Dog extends Animal{  
    void eat(){System.out.println("eating bone");}  
    }  
    class Cat extends Animal{  
    void eat(){System.out.println("eating mouse");}  
    }  
    class Lion extends Animal{  
    void eat(){System.out.println("eating prey");}  
    }  
    class TestPolymorphism3{  
    public static void main(String[] args){  
    Animal a;  
    a=new Dog();  
    a.eat();  
    a=new Cat();  
    a.eat();  
    a = new Lion();  
    a.eat();  
    }}  
    

    Output:

    eating bone
    eating mouse
    eating prey
    

    Java Runtime Polymorphism with Multilevel Inheritance
    class Animal{  
    void eat(){System.out.println("eating...");}  
    }  
    class Lion extends Animal{  
    void eat(){System.out.println("eating prey");}  
    }  
    class BabyLion extends Dog{  
    void eat(){System.out.println("drinking milk");}  
    public static void main(String args[]){  
    Animal a1,a2,a3;  
    a1 = new Animal();  
    a2 = new Lion();  
    a3 = new BabyLion();  
    a1.eat();  
    a2.eat();  
    a3.eat();  
    }}  
    

    Output:

    eating...
    eating prey
    drinking milk
    

    Upcasting

    Upcasting: reference variable of Parent class refers to the object of Child class.

    class Parent {}  
    class Child extends Parent {} 
    
    Parent obj = new Child();//upcasting  
    

    Reference variable of class type or an interface type can be used.

    interface Interface {}  
    class Parent {}  
    class Child extends Parent implements Interface {}  
    

    Here, the relationship of Child class would be:

    1. Child IS-A Parent
    2. Child IS-A Interface
    3. Child IS-A Object

    Object is the root class of all classes in Java, so we can write Child IS-A Object.

    class Animal{  
      void run(){System.out.println("Running");}  
    }  
    class Cheetah extends Animal{  
      void run(){System.out.println("Running as fast as 75km/h");}  
      
      public static void main(String args[]){  
        Animal myCheetah = new Cheetah();//upcasting  
        b.run();  
      }  
    } 
    

    Output:

    Running as fast as 75km/h
    
    1. Cheetah class extends Animal class and overrides its run() method.
    2. run method is called by the reference variable of Parent class.
    3. It refers to the Subclass object and Subclass method overrides the Parent class method,
      so the subclass method is invoked at runtime.
    4. Since method invocation is determined by the JVM not compiler, it is known as runtime polymorphism.

    Covariant Return Type in Method Overriding
    1. A subclass overrides a method whose return type is Non-Primitive
    2. A subclass overrides a method by changing its return type to subclass type.
    class A{  
    A get(){return this;}  
    }  
      
    class B1 extends A{  
    B1 get(){return this;}  
    void message(){System.out.println("welcome to covariant return type");}  
      
    public static void main(String args[]){  
    new B1().get().message();  
    } }
    

    Output:

    welcome to covariant return type
    

    Java Runtime Polymorphism can’t be achieved by Data Members

    A method is overridden, not the data members.

    class Cheetah {  
     int speedLimit = 75;  
    }  
    class Rocket extends Cheetah {  
     int speedLimit = 17600;  
      
     public static void main(String args[]){  
      Cheetah obj = new Rocket();  
      System.out.println(obj.speedLimit); 
    }  
    
    1. Both the classes have a data member speedLimit.
    2. Data member is accessed by the reference variable of Parent class, which refers to the subclass object.
    3. Data member is not overridden, so data member of the Parent class will be accessed.

    Output:

    75
    

    A static method cannot be overridden

    Static methods cannot be overridden because they are not dispatched on the object instance at runtime.
    The compiler decides which method gets called.

    1. Static method is bound with class
      whereas instance method is bound with an object.
    2. Stack Memory in Java is used for static memory allocation, and an instance belongs to the heap area.

    Read more about memory allocation in Java >>>

    A static method can be overloaded

    Static methods can be overloaded (meaning that you can have the same method name for several methods as long as they have different parameter types).
    Read more about Java Method Overloading >>>

    Java main method cannot be overridden

    We cannot override Java main method because main is a static method.

    1. Use:
      • Method overloading is used to increase the readability of the program.
      • Method overriding is used to provide the specific implementation of its super class method.
    2. Where occurs:
      • Method overloading is performed within child class.
      • Method overriding occurs in two classes with IS-A (inheritance) relationship.
    3. Parameters:
      • Method overloading: parameter must be different.
      • Method overriding: parameter must be same.
    4. Polymorphism type
      • Method overloading is the example of compile-time polymorphism (static binding) .
      • Method overriding is the example of run-time polymorphism (dynamic binding).
    5. Method return type:
      • Method overloading can’t be performed by changing return type of the method only.
        Return type can be same or different in method overloading.
        But you must have to change the parameter.
      • Method overriding: return type must be same or covariant.

    Coupling refers to the knowledge or information or dependency of another class.
    It arises when classes are aware of each other.

    Levels of coupling
    1. If a class has the details information of another class, there is strong coupling.
    2. In Java, we use private, protected, and public modifiers to display the visibility level of a class, method, and field.
    3. You can use interfaces for the weaker coupling because there is no concrete implementation.

    Cohesion refers to the level of a component that performs a single well-defined task.

    Levels of Cohesion
    • A single well-defined task is done by a highly cohesive method.
    • The weakly cohesive method will split the task into separate parts.

    The java.io package is a highly cohesive package because it has I/O related classes and interface.
    However, the java.util package is a weakly cohesive package because it has unrelated classes and interfaces.



    Leave a Reply or Comment

    Your email address will not be published. Required fields are marked *