Inheritance, Extends

class Animal {
    // field and method of the parent class
    String name;
    public void eat() {
        System.out.println("I can eat");
    }
}
  
// inherit from Animal
class Dog extends Animal {
    // new method in subclass
    public void display() {
        System.out.println("My name is " + name);
    }
}
  
class Main {
    public static void main(String[] args) {
  
        // create an object of the subclass
        Dog gs = new Dog();
  
        // access field of superclass
        gs.name = "Max";
        gs.display();
  
        // call method of superclass
        // using object of subclass
        gs.eat();
  
    }
}

Main.main(null);
My name is Max
I can eat

Subclass constructor, super Keyword

  • Uses of super keyword
    • To call methods of the superclass that is overridden in the subclass.
    • To access attributes (fields) of the superclass if both superclass and subclass have attributes with the same name.
    • To explicitly call superclass no-arg (default) or parameterized constructor from the subclass constructor.
/**
 * super to Call Superclass Method
 */

class Animal {

    // overridden method
    public void display(){
        System.out.println("I am an animal");
    }
}
  
  class Dog extends Animal {
  
    // overriding method
    @Override
    public void display(){
        System.out.println("I am a dog");
    }
  
    public void printMessage(){
        // this calls overriding method
        display();

        // this calls overridden method
        super.display();
    }
}
  
  class Main {
    public static void main(String[] args) {
        Dog dog1 = new Dog();
        dog1.printMessage();
    }
}

Main.main(null);
I am a dog
I am an animal
/**
 * Access superclass attribute
 */

class Animal {
    protected String type="animal";
}
  
  class Dog extends Animal {
    public String type="mammal";
  
    public void printType() {
        System.out.println("I am a " + type);
        System.out.println("I am an " + super.type);
    }
}
  
  class Main {
    public static void main(String[] args) {
        Dog dog1 = new Dog();
        dog1.printType();
    }
}

Main.main(null);
I am a mammal
I am an animal

Overloading a method, same name different parameters

class MethodOverloading {

    // this method accepts int object
    private static void display(int a){
        System.out.println("Got Integer data.");
    }

    // this method accepts String object
    private static void display(String a){
        System.out.println("Got String object.");
    }

    public static void main(String[] args) {
        display(1);
        display("Hello");
    }
}

MethodOverloading.main(null);
Got Integer data.
Got String object.

Overriding a method, same signature of a method

/**
 * Method Overriding
 */

class Animal {

    // overridden method
    public void display(){
        System.out.println("I am an animal");
    }
}

class Dog extends Animal {
  
    // overriding method
    @Override
    public void display(){
        System.out.println("I am a dog");
    }
  
    public void printMessage(){
        display();
    }
}
  
class Main {
    public static void main(String[] args) {
        Dog dog1 = new Dog();
        dog1.printMessage();
    }
}

Main.main(null);
I am a dog

Abstract Class, Abstract Method

  • Data abstraction is the process of hiding certain details and showing only essential information to the user
  • Abstraction can be achieved with either abstract classes or interfaces
// Abstract class
abstract class Animal {
    // Abstract method (does not have a body)
    public abstract void animalSound();
    // Regular method
    public void sleep() {
        System.out.println("Zzz");
    }
}
  
// Subclass (inherit from Animal)
class Pig extends Animal {
    public void animalSound() {
      // The body of animalSound() is provided here
      System.out.println("The pig says: wee wee");
    }
}
  
class Main {
    public static void main(String[] args) {
        Pig myPig = new Pig(); // Create a Pig object
        myPig.animalSound();
        myPig.sleep();
    }
}

Main.main(null);
The pig says: wee wee
Zzz

Standard methods: toString(), equals(), hashCode()

  • Mainly used with objects, arrays, and arraylists
/**
 * hashCode()
 */

ArrayList<String> arrli = new ArrayList<String>();
arrli.add("Hello");
arrli.add("Howdy");
arrli.add("Hey");
arrli.add("Hi");

System.out.println(arrli);
System.out.println(arrli.hashCode());
[Hello, Howdy, Hey, Hi]
2041636537
/**
 * toString()
 */

class Friend {
 
    // Member attributes of this class
    String name;
    int age;
    int grade;
 
    // Constructor of this class
    Friend(String name, int age, int grade)
    {
        // This variable refers to current instance itself
        this.name = name;
        this.age = age;
        this.grade = grade;
    }
 
    public String toString() {
        return name + ", " + age + ", " + grade;
    }

    // Method of this class
    // Main driver method
    public static void main(String[] args)
    {
 
        // Creating an object of this class
        // Custom attributes been passed as in arguments
        Friend b = new Friend("Yash Shah", 17, 12);
 
        // Print and display commands to illustrate
        // toString() method as both will print the same
        // Print the object
        System.out.println(b.hashCode());
        // Print the object but implicitly using toString()
        // method
        System.out.println(b.toString());
    }
}

Best_Friend.main(null);
905115276
Yash Shah, 17, 12
/**
 * equals()
 */

public class EqualsExample{
    public static void main(String args[]){
        String compare1 = "java";
        String compare2 = "java";
        String compare3 = "JAVA";
        String compare4 = "python";
        
        //true because content and case is same
        System.out.println(compare1.equals(compare2));
        
        //false because case is not same
        System.out.println(compare1.equals(compare3));
        
        //false because content is not same
        System.out.println(compare1.equals(compare4));
    }
}

EqualsExample.main(null);
true
false
false

Late binding of object, referencing superclass object

Animal a = new Chicken();
Animal b = new Goat();

Polymorphism: any of overloading, overriding, late binding

  • Polymorphism is the ability to have multiple methods with the same name but different parameters. This is useful when you want to have multiple methods that do the same thing but with different parameters. This is also useful when you want to have a method that can take multiple types of parameters.
    • Overloading is when you have multiple methods with the same name but different parameters.
    • Overriding is when you have a method with the same name and parameters as a method in a superclass but you want to modify the method in the subclass.
    • Late binding is when you have allow the compiler to determine which method to use at runtime instead of compile time. Abstract Class - Objects cannot be created from an abstract class, they can only be extended. This is useful when you want to create a class that can be extended but not instantiated.
public class PolymorphismExample {
    public void testOutput(int x) {
        System.out.println("Integer: " + x);
    }

    public void testOutput(String x) {
        System.out.println("String: " + x);
    }
    
    public void testOutput(double x) {
        System.out.println("Double: " + x);
    }

}

PolymorphismExample pe = new PolymorphismExample();
System.out.println("Polymorphism Example:");
pe.testOutput(5);
pe.testOutput("Hello");
pe.testOutput(5.5);
Polymorphism Example:
Integer: 5
String: Hello
Double: 5.5
Complexity Equation
O(N!) Factorial
O(2^N) Exponential
O(N^3) Cubic
O(N^2) Quadratic
O(N Log N) N * Log N
O(N) Linear
O(Log N) Logarithmic
O(1) Constant
/**
 * Binary Search - O(Log N)
 */

public class BinarySearch {

    // Searching using Recursive approach
    public static int Search(int arr[], int value, int start, int end) {
        int center = (start + end) / 2;

        if (start <= end) {
            if (value == center) {
                return center;
            }

            if (value < center) {
                return Search(arr, value, start, center - 1);
            }

            if (value > center) {
                return Search(arr, value, center + 1, end);
            }
        }

        return -1;
    }

    public static void main(String[] args) {
        int arr[] = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };

        int Index = Search(arr, 9, 0, arr.length);
        if (Index == -1) {
            System.out.println("Value Not Found");
        } else {
            System.out.println("Value found at Index: " + Index);
        }
    }
}

BinarySearch.main(null);
Value found at Index: 9