Back to Blog
Java

Java Overridden Method Access Modifier: Rules and Examples

java overridden method access modifier: Learn the Java rule that overridden methods cannot reduce visibility, with examples, common errors, and design implications.

Javamethod overridingaccess modifierspolymorphismLiskov substitution@Override
A Java method override showing access modifier hierarchy from private to public with an arrow indicating allowed direction.

When you override a method in Java, the access modifier of the overriding method must be the same or more permissive than the access modifier of the method it overrides. This rule is a core part of the java overridden method access modifier behavior, and violating it produces a compile-time error. This article explains the rule, why it exists, and how to apply it correctly in real code.

The Access Modifier Rule for Overridden Methods

In Java, method overriding allows a subclass to provide a specific implementation of a method declared in a superclass. The overriding method must have the same name, parameter list, and return type (or a covariant return type). In addition, the access modifier of the overriding method cannot be more restrictive than the access modifier of the overridden method. In other words, you cannot reduce the visibility of a method when you override it.

The Java compiler enforces this rule to preserve the contract established by the superclass. If a superclass declares a method as public, every subclass must keep it public. If the superclass method is protected, the subclass can keep it protected or make it public, but it cannot make it package-private or private. This ensures that any code that can legally call the method on a superclass reference will also be able to call it on a subclass instance, preserving polymorphism.

The Visibility Hierarchy in Java

Java defines four access levels, from most restrictive to least restrictive:

Access ModifierVisibility
privateOnly within the same class
(default)Within the same package
protectedSame package or subclasses
publicAnywhere

When overriding, the new access modifier must be at the same level or higher in this hierarchy. For example, a protected method can be overridden as protected or public, but not as package-private or private. A public method must remain public in every subclass.

The rationale is the Liskov substitution principle: a subclass instance must be usable wherever a superclass instance is expected. If a superclass method is public and a subclass narrows it to protected, code that calls the method through a superclass reference would break at runtime when the actual object is of the subclass type.

Increasing Visibility: When and Why

You can increase the visibility of an overridden method. This is often done when a subclass wants to expose a method that was previously restricted. For example, a superclass might define a protected helper method that subclasses can use internally. A particular subclass may decide that this helper is useful to external callers and promote it to public.

class Base { protected void helper() { // internal logic } } class Derived extends Base { @Override public void helper() { super.helper(); // additional logic } }

Here, Derived.helper() is public, which is more permissive than protected. This is legal and often intentional. However, increasing visibility is a design decision that should be made deliberately. Exposing a method that was previously hidden from external callers changes the class's public API and may have maintenance implications.

Common Compilation Errors and Their Causes

The most common mistake is attempting to reduce visibility. Consider this code:

class Animal { public void eat() { System.out.println("Animal eating"); } } class Dog extends Animal { @Override protected void eat() { // compile error System.out.println("Dog eating"); } }

The compiler reports an error similar to: eat() in Dog cannot override eat() in Animal; attempting to assign weaker access privileges; was public. This error message clearly states the problem: you are trying to make a public method less accessible.

The same error occurs when you try to change a protected method to package-private or private. The compiler checks the access modifier of the overridden method and rejects any reduction.

Access Modifiers and Method Overloading vs. Overriding

It is important to distinguish between method overriding and method overloading. Overloading occurs when you define multiple methods with the same name but different parameter lists in the same class. Access modifiers for overloaded methods are independent; each overload can have its own access level. Overriding, on the other hand, requires the same signature (name and parameter types) and is subject to the access modifier rule.

A common pitfall is accidentally overloading instead of overriding when the parameter list differs. In that case, the access modifier rule does not apply, and you may end up with two methods that behave differently than intended. Always use the @Override annotation to ensure you are actually overriding a superclass method.

Interaction with Abstract Methods and Interfaces

When a class implements an interface, all methods declared in the interface are implicitly public. Therefore, the implementing method must be public as well. You cannot reduce the visibility of an interface method to protected or package-private. This is a direct consequence of the rule: since the interface method is public, the implementation must be public.

For abstract classes, the same rule applies. If an abstract method is protected, the concrete implementation can be protected or public, but not package-private or private. If the abstract method is public, the implementation must be public.

Edge Cases: Private and Static Methods

Private methods are not inherited and therefore cannot be overridden. If a subclass declares a method with the same name and signature as a private method in the superclass, it is a new method, not an override. Consequently, the access modifier rule does not apply. You can freely change the access modifier of such a method.

Static methods are hidden, not overridden, when a subclass declares a static method with the same signature. The access modifier rule for static methods is more lenient: the compiler does not enforce the same visibility restriction. However, hiding a static method with a different access modifier can lead to confusing behavior, so it is generally recommended to keep the access modifier the same.

Using @Override to Catch Access Modifier Mistakes

The @Override annotation is a compile-time check that the method is indeed overriding a superclass method. If you attempt to override a method with an invalid access modifier, the compiler will still produce an error even without the annotation. However, the annotation helps in a different way: it catches cases where you think you are overriding but are actually overloading or declaring a new method. For example, if you accidentally change the parameter list, the method will not override, and the @Override annotation will trigger a compile error.

Using @Override consistently is a good practice because it makes your intent explicit and allows the compiler to verify that the method signature matches a superclass method. This is especially useful when you are increasing visibility, because it confirms that the method is indeed an override and not a new method.

java overridden method access modifier: Practical Usage and | RYUSLOG DEV