[!INDEX]

  1. Def. - subclass provides a specific implementation
  2. Points + same + override + access + exception + constructor
  3. Example one ( animal, dog, cat + makeSound mt
  4. Covariant object - string + allow a mt() in a subclass to return...
  5. Reasons for Covariant Return Types
  6. Practical Example code with ( animal and dog return type )
  7. Access Modifier ( From protected to public )
  8. Why subclass can make the method more accessible
  9. Unchecked Exception in child only
  10. Rules for Exceptions in Method Overriding
  11. checked e/x in child only
  12. child and parent throw same run time e/x
  13. Parent Throws Parent Exception, Child Throws Child Exception
  14. Pt. Throws Unchecked E/x, Child Attempts to Throw Checked E/x

1 - Definition + subclass provides a specific implementation

[!NOTE]

  1. a subclass provides a specific implementation for a method that is already defined in its superclass. This allows a subclass to offer a specific implementation while maintaining the method signature from the superclass.

2 - Points + same + override + access + exception + constructor

[!NOTE]

  1. Same Method Signature: subclass mt must have the same name, return type, and parameters as in the superclass.

  2. @Override Annotation: It's a good practice to use the @Override annotation above the method in the subclass.

  3. Access Level: The access level of the overriding method cannot be more restrictive than the overridden method.

  4. Exceptions: can throw any unchecked (runtime) e/x, but it can only throw checked exceptions that are declared in the overridden method or their subclasses.

  5. Constructor: Constructors cannot be overridden. They can be overloaded, but not overridden.


3 - Example one ( animal, dog, cat + makeSound mt

class Animal {
    void makeSound() {
        System.out.println("Animal makes a sound");
    }
}
class Dog extends Animal {
    @Override
    void makeSound() {
        System.out.println("Dog barks");
    }
}
class Cat extends Animal {
    @Override
    void makeSound() {
        System.out.println("Cat meows");
    }
}
public class Main {
    public static void main(String[] args) {
        Animal myAnimal1 = new Dog();
        myAnimal1.makeSound();  // Output: Dog barks

        Animal myAnimal2 = new Cat();
        myAnimal2.makeSound();  // Output: Cat meows
    }
}

[!important]

  1. Reference Type: Animal - This means myAnimal1 can call any method that is declared in the Animal class.
  2. Object Type: Dog - This means myAnimal1 actually points to a Dog object, and if the Dog class has overridden a method from Animal, the Dog's version of the method will be called.
  3. allows a subclass object to be treated as an instance of its superclass. In this case, Dog is a subclass of Animal.
  4. The reference type (Animal) determines what methods can be called, while the actual object's type (Dog or Cat) determines which implementation of the method is executed.

4 - Covariant object - string + allow a mt() in a subclass to return...

[!NOTE]

  1. allow a method in a subclass to return a type that is a subclass of the return type of the method in the superclass.

public class G05 {
    Object show(String a) {
        System.out.println("covariant return type-1");
        return null;
    }
}
class Xyz extends G05 {
    @Override
    String show(String a) {
        System.out.println("covariant return type-2");
        return null;
    }
    public static void main(String[] args) {
        G05 t = new G05();
        t.show("monika");  // Output: covariant return type-1

        Xyz x = new Xyz();
        x.show("jyoti");  // Output: covariant return type-2
    }
}

5 - Reasons for Covariant Return Types

[!NOTE]

  1. Enhanced Type Safety:

    • This enhances type safety by ensuring that the returned objects are of a specific type expected by the subclass method.
  2. Improved Code Readability and Maintainability:

    • When a method in a subclass returns a more specific type, it is clear to the reader what type of object is being returned, reducing the need for type casting and making the code more understandable.
  3. Better Polymorphism Support:

    • support polymorphism by allowing methods to be overridden with more specific return types, which can be used more flexibly in polymorphic code. This allows methods to return the most appropriate type for the context in which they are used.
  4. Consistency with Object-Oriented Principles:

    • Covariant return types align with the principles of inheritance and polymorphism in object-oriented programming. They allow subclasses to refine and specialize behavior defined in super classes, providing a more natural and consistent extension of the class hierarchy.

6 - Practical Example code with ( animal and dog return type )

[!NOTE]

  1. Consider a practical scenario involving a base class Animal and a subclass Dog. Covariant return types allow the subclass to override a method with a more specific return type.

class Animal {
    Animal makeSound() {
        System.out.println("Animal makes a sound");
        return new Animal();
    }
}
class Dog extends Animal {
    @Override
    Dog makeSound() {
        System.out.println("Dog barks");
        return new Dog();
    }
    public static void main(String[] args) {
        Animal animal = new Animal();
        animal.makeSound();  // Output: Animal makes a sound

        Dog dog = new Dog();
        dog.makeSound();  // Output: Dog barks

        Animal polyAnimal = new Dog();
        polyAnimal.makeSound();  // Output: Dog barks
    }
}

7 - Access Modifier ( From protected to public )

public class G09 {
    protected void show(String a) {
        System.out.println("protected - public-1");
    }
}
class Xyz extends G09 {
    @Override
    public void show(String a) {
        System.out.println("protected - public-2");
    }
    public static void main(String[] args) {
        G09 t = new G09();
        t.show("monika");  // Output: protected - public-1

        Xyz x = new Xyz();
        x.show("jyoti");  // Output: protected - public-2
    }
}

8 - Why subclass can make the method more accessible

[!NOTE]

  1. Maintaining Substitutability:

    • The principle of substitutability (part of the Liskov Substitution Principle) dictates that objects of a subclass should be able to replace objects of the superclass without altering the desirable properties of the program. If a subclass method were to reduce visibility, it could break this substitutability. For example, ==if a method in the superclass is public, the subclass should not restrict access to that method, as this would limit the functionality and accessibility expected by clients using the superclass.==
  2. Access Control Consistency:

    • ==Java’s access control mechanism ensures that visibility rules are consistent across class hierarchies. Allowing only an increase in visibility ensures that the subclass adheres to the visibility constraints established by the superclass.== This prevents scenarios where a subclass would restrict access to methods, which could lead to confusion or errors if the subclass is used polymorphically.
  3. Polymorphism and Inheritance:

    • Inheritance in Java implies that a subclass inherits the behavior (methods) of its superclass. When a method is overridden, it should be accessible in the same way as it was in the superclass. ==Increasing visibility makes sense because the subclass might need to expose additional functionality, but decreasing visibility could prevent clients from accessing the method when using the subclass.==
  4. Encapsulation:

    • Encapsulation is a core principle of object-oriented programming. ==By allowing only an increase in visibility, Java ensures that the encapsulation provided by the superclass is maintained or enhanced in subclasses.== Reducing visibility would break this encapsulation and could lead to design inconsistencies.
  5. Client Expectations:

    • Clients of a class expect that if a method is available in the superclass, it will remain available in the subclass. If a subclass were allowed to reduce visibility, it would violate the expectations of code that depends on the superclass method being available, potentially causing runtime issues.

9 - Unchecked Exception in child only

public class G11 {
    void show() {
        System.out.println("parent ok - child only Unchecked -1");
    }
}
class Xyz extends G11 {
    @Override
    void show() throws ArithmeticException {
        System.out.println("parent ok - child only Unchecked -2");
    }
    public static void main(String[] args) {
        G11 t = new G11();
        t.show();  // Output: parent ok - child only Unchecked -1

        Xyz x = new Xyz();
        x.show();  // Output: parent ok - child only Unchecked -2
    }
}

10 - Rules for Exceptions in Method Overriding

[!NOTE]

  1. Unchecked Exceptions:

    • A method in a subclass can throw any unchecked exception, regardless of whether the method in the superclass throws an exception or not.
    • This is because ==unchecked exceptions do not need to be declared in the method== signature and are not checked at compile-time.
  2. Checked Exceptions:


11 - checked e/x in child only

public class G12 {
    void show() {
        System.out.println("parent ok - child checked, error -1");
    }
}
class Xyz extends G12 {
    @Override
    void show() throws Exception {  // This will cause a compile-time error
        System.out.println("parent ok - child checked, error -2");
    }
    public static void main(String[] args) {
        G12 t = new G12();
        t.show();  // Output: parent ok - child checked, error -1

        Xyz x = new Xyz();
        x.show();  // Output: parent ok - child checked, error -2
    }
}

[!NOTE] Java's rules for method overriding ensure that a subclass ==does not introduce new checked== exceptions that the caller might not be prepared to handle. In this case, since the parent class method show does not throw any checked exceptions, the child class method cannot declare that it throws a checked exception like Exception.

To fix this, either the ==parent method must also declare the exception==, or the child method must ==not throw== any new checked exceptions.


12 - child and parent throw same run time e/x

public class G13 {
    void show() throws RuntimeException {
        System.out.println("parent - child same exception -1");
    }
}
class Xyz extends G13 {
    @Override
    void show() throws RuntimeException {
        System.out.println("parent - child same exception -2");
    }
    public static void main(String[] args) {
        G13 t = new G13();
        t.show();  // Output: parent - child same exception -1

        Xyz x = new Xyz();
        x.show();  // Output: parent - child same exception -2
    }
}

[!NOTE]


13 - Parent Throws Parent Exception, Child Throws Child Exception

public class G14 {
    void show() throws RuntimeException {
        System.out.println("parent exception to child exception -1");
    }
}
class Xyz extends G14 {
    @Override
    void show() throws ArithmeticException {
        System.out.println("parent exception to child exception -2");
    }
    public static void main(String[] args) {
        G14 t = new G14();
        t.show();  // Output: parent exception to child exception -1

        Xyz x = new Xyz();
        x.show();  // Output: parent exception to child exception -2
    }
}

[!NOTE]


14 - Pt. Throws Unchecked E/x, Child Attempts to Throw Checked E/x

public class G15 {
    void show() throws RuntimeException {
        System.out.println("parent exception to child exception -1");
    }
}
class Xyz extends G15 {
    @Override
    void show() throws Exception {  // This will cause a compile-time error
        System.out.println("parent exception to child exception -2");
    }
    public static void main(String[] args) {
        G15 t = new G15();
        t.show();  // Output: parent exception to child exception -1

        Xyz x = new Xyz();
        x.show();  // This line will not compile
    }
}

[!NOTE]

  1. This is not allowed in Java because a method in a subclass cannot throw a broader exception than the method it overrides in the superclass.