• Home
  • LLMs
  • Docker
  • Kubernetes
  • Java
  • All
  • About
Java | Method Overriding
  1. Overriding a Method
  2. Rules of Method Overriding
  3. Implementing Interface Methods

  1. Overriding a Method
    Method overriding allows a subclass to provide a specific implementation of a method already defined in one of its superclasses.

    The superclass version of the method can be invoked from the subclass code using the super keyword (example: super.doCallOverriddenMethod()).

    Note: Overriding is a concept that applies only to methods, not to variables.
  2. Rules of Method Overriding
    • Method overriding is only possible for methods that are inheritable.
      For example, a method marked private is not inheritable and therefore cannot be overridden.
      However, you can define a method in the subclass with the same name, signature (parameters), and return type, but in this case, it's treated as a new method completely unrelated to the one in the superclass.

    • A subclass in the same package as the superclass can override any method that is not marked private or final.

    • A subclass in a different package can override only those methods marked public or protected (and not marked final).

    • You cannot override a method marked final.
      The compiler will show an error: "Cannot override the final method from SuperClass"
      public class SuperClass {
          public final Integer subtractOperation(Integer value1, Integer value2) {
              return (value1 - value2);
          }
      }
      public class SubClass extends SuperClass {
          public Integer subtractOperation(Integer value1, Integer value2) { // compiler error: Cannot override the final method from SuperClass
              return (value1 - value2) * 10;
          }
      }
    • You cannot override a method marked static.
      The compiler will show an error: "This instance method cannot override the static method from SuperClass"
      public class SuperClass {
          public static Integer subtractOperation(Integer value1, Integer value2) {
              return (value1 - value2);
          }
      }
      public class SubClass extends SuperClass {
          public Integer subtractOperation(Integer value1, Integer value2) { // compiler error: This instance method cannot override the static method from SuperClass
              return (value1 - value2) * 10;
          }
      }
      However, it is valid to declare the subclass method as static too; in this case, it is a new method that hides the superclass method (method hiding, not overriding).
      When both methods are static, the method version called depends on the declared type of the variable, not the actual object instance.
      public class SubClass extends SuperClass {
          public static Integer subtractOperation(Integer value1, Integer value2) {
              return (value1 - value2) * 10;
          }
      }
      public class TestClass {
          public static void main(String[] args) {
              SuperClass superClass1 = new SuperClass();
              SuperClass superClass2 = new SubClass();
              SubClass subClass1 = new SubClass();
      
              System.out.println(superClass1.subtractOperation(5, 2)); // prints 3: uses SuperClass version
              System.out.println(superClass2.subtractOperation(5, 2)); // prints 3: uses SuperClass version
              System.out.println(subClass1.subtractOperation(5, 2)); // prints 30: uses SubClass version
      
              System.out.println();
      
              System.out.println(SuperClass.subtractOperation(5, 2)); // prints 3
              System.out.println(SubClass.subtractOperation(5, 2)); // prints 30
          }
      }
    • To be considered an overriding method, the method signature must exactly match that of the superclass method.
      The method signature includes the method name and parameter list (number, types, and order of parameters).

      Each parameter in the subclass method must be of the same type as the corresponding parameter in the superclass method.

      If the number of parameters is different or their types differ (even if it's a subtype), it is not considered overriding but method overloading (a completely new method).
      public class SuperClass {
          public void doSomething(SuperClass superClass) { }
      }
      public class SubClass extends SuperClass {
          public void doSomething(SuperClass superClass) { } // overriding
      
          public void doSomething(SubClass subClass) { } // overloading (new method)
      
          public void doSomething(SubClass subClass1, SubClass subClass2) { } // overloading (new method)
      }
      Details about method overloading will be discussed on a separate page (Method Overloading), but for now, note that the method selected at compile time depends on the argument types.
      public class TestClass {
          public static void main(String[] args) {
              SuperClass superClass1 = new SuperClass();
              SuperClass superClass2 = new SubClass();
              SubClass subClass1 = new SubClass();
      
              superClass1.doSomething(superClass1); // calls SuperClass version
              superClass1.doSomething(subClass1); // calls SuperClass version
      
              superClass2.doSomething(superClass1); // calls SubClass version
              superClass2.doSomething(subClass1); // calls SubClass version
      
              subClass1.doSomething(superClass1); // calls SubClass version
              subClass1.doSomething(subClass1); // calls overloaded method in SubClass (SubClass parameter)
      
              subClass1.doSomething(subClass1, subClass1); // calls another overloaded method in SubClass
          }
      }
    • The return type of the overriding method must be the same or a subtype of the return type of the superclass method (covariant return type).
      If the return type is incompatible, the compiler will throw an error.
      public class SuperClass {
          public SuperClass doSomething() { return null; }
      }
      public class SubClass extends SuperClass {
          public Object doSomething() { return null; } // compiler error: The return type is incompatible with SuperClass.doSomething()
      }
      To fix this, the return type should be changed to either SuperClass or SubClass.

      Note that if the parameter lists differ, this rule does not apply since it's not considered overriding but overloading.

    • The visibility (access modifier) of the overriding method cannot be more restrictive than that of the superclass method.
      For example, you cannot override a public method and declare it as protected or private:
      public class SuperClass {
          public void doSomething() { }
      }
      public class SubClass extends SuperClass {
          protected void doSomething() { } // compiler error: Cannot reduce the visibility of the inherited method from SuperClass
      }
    • The visibility of the overriding method can be less restrictive (more accessible).
      For example, you can override a protected method and declare it as public:
      public class SuperClass {
          protected void doSomething() { }
      }
      public class SubClass extends SuperClass {
          public void doSomething() { }
      }
    • The overriding method can throw any unchecked exception (runtime exceptions and errors), regardless of whether the superclass method throws an exception or not.
      public class SuperClass {
          public void doSomething() { }
      }
      public class SubClass extends SuperClass {
          public void doSomething() throws RuntimeException { }
      }
    • The overriding method cannot throw checked exceptions that are not declared by the superclass method.
      public class SuperClass {
          public void doSomething() { }
      }
      public class SubClass extends SuperClass {
          public void doSomething() throws FileNotFoundException { } // compiler error: Exception FileNotFoundException is not compatible with throws clause in SuperClass.doSomething()
      }
    • The overriding method may choose not to throw checked exceptions that the superclass method declares.
      public class SuperClass {
          public void doSomething() throws FileNotFoundException { }
      }
      public class SubClass extends SuperClass {
          public void doSomething() { }
      }
      Note that the compiler only considers the declared type of the variable when determining whether to require a try-catch block.
      public class TestClass {
          public static void main(String[] args) {
              SuperClass superClass1 = new SuperClass();
              SuperClass superClass2 = new SubClass();
              SubClass subClass1 = new SubClass();
      
              superClass1.doSomething(); // compiler error: Unhandled exception type FileNotFoundException
              superClass2.doSomething(); // compiler error: Unhandled exception type FileNotFoundException
              subClass1.doSomething(); // OK
          }
      }
    • The overriding method can only throw checked exceptions that are the same or subtypes of those thrown by the superclass method.
      public class SuperClass {
          public void doSomething() throws IOException { }
      }
      public class SubClass extends SuperClass {
          public void doSomething() throws FileNotFoundException, ZipException { }
      }
      Otherwise, the compiler will display an error:
      public class SuperClass {
          public void doSomething() throws FileNotFoundException { }
      }
      public class SubClass extends SuperClass {
          public void doSomething() throws IOException { } // compiler error: Exception IOException is not compatible with throws clause in SuperClass.doSomething()
      }
  3. Implementing Interface Methods
    A (non-abstract) class must implement all the methods declared in the interfaces it implements.
    The implementation must follow the same rules outlined above for method overriding.

    • The parameter list (and their types) must match exactly those of the interface method.

    • The return type must be the same or a subtype of the interface method's return type.

    • The visibility of the implemented method cannot be more restrictive than the interface method.
      Since interface methods are implicitly public, the implementing method must be declared public.

    • The implemented method can throw any unchecked exception, regardless of whether the interface method declares it or not.

    • The implemented method cannot throw checked exceptions that are not declared by the interface method.

    • The implemented method may choose not to throw the checked exceptions declared by the interface method.

    • The implemented method can throw only those checked exceptions that are the same or subtypes of those declared by the interface method.
© 2025  mtitek