Innovation
Innovation

Reputation: 1534

Overriding method with a lower-visibility one results in compilation error

I have one class and one interface:

public interface A {
    public void getNum();
}

public class B {
    public void getNum() {
        System.out.println("4");
    }
}

public class C extends B implements A {
    protected void getNum() {
        System.out.println("3");
    }
}

Now my question is, why this code is giving compilation error and how can we avoid it. Is there any way in which we can override this method in class C?

Upvotes: 4

Views: 3431

Answers (8)

Pshemo
Pshemo

Reputation: 124225

From Java Language Specification:

jls-8.4.8.3

The access modifier (§6.6) of an overriding or hiding method must provide at least as much access as the overridden or hidden method, as follows:

  • If the overridden or hidden method is public, then the overriding or hiding method must be public; otherwise, a compile-time error occurs.
  • ...

Notice that you are trying to override public method getNum() inherited from class B (and also from interface A) with new one that has protected access modifier. It means that you are trying to reduce visibility of this method which according to specification is incorrect.
To be able to override this method you need to use public access modifier with your new version of that method.


Why you cant reduce visibility? Take a look at below code which uses your classes but is placed inside some other package and ask yourself "how should this code behave?".

package my.pckage;

import your.pckage.A;
import your.pckage.C;

public class Test{
    public static void main (String[] args){
        C C = new C();
        c.getNum();// ERROR: Test class doesn't have access to `c`s protected method.
                   // Why should it have, Test doesn't extend C.

        A a = (A)c;// Lets try using other reference
        a.getNum();// Should `a` have access to method that is protected in `C`?
                   // If yes, then what is the point of declaring this method 
                   // protected if all I would have to do to get access to it is 
                   // casting instance of C to A interface?
    }
}

Upvotes: 13

shrey
shrey

Reputation: 863

First of all scope should be from lower to higher while you are overriding method in Java. scope of subclass method should be high then super class for e.g

Valid Overriding

class B {
    protected void getNum() {
        System.out.println("4");
    }

 class C extends B  {
    public void getNum() {
        System.out.println("3");
    }

InValid Overriding

class B {
    public void getNum() {
        System.out.println("4");
    }

class C extends B  {
    protected void getNum() {
        System.out.println("3");
    }

Your second problem is you have created two public class which is not valid you can create only one public class in your java file.

Upvotes: 6

Shrimpsy
Shrimpsy

Reputation: 21

As stated, only one public class can be used per file. So, to have them all public, one must create three separate .java files. I will write the code up below, as well as detailing how to override the method to use the correct version of it in each case.

One may always have methods with the same name, but for overriding, they must have different argument lists. This is one of the compiler errors, you have three methods with the same argument lists, namely none. You may create and call the method with the correct argument list to achieve the desired result.

A.java:

package stackOverflow.tests; // Sample package for visibility

public Interface A {
    public void getNum(int a); // Method takes a single integer argument
}

B.java:

package stackOverflow.tests;

public class B {
    protected void getNum(int a, int b) { // Method takes two integer arguments, differing in the argument list but equal in name
        System.out.println("4");
    }
}

C.java:

package stackOverflow.tests;

import stackOverflow.tests.A; // Importing both classes to use their methods
import stackOverflow.tests.B;

public class C extends B implements A {
    public void getNum(int a, String x) { // Takes an integer and a string argument
            System.out.println("3");    
    }    

    public void getNum(int a) {
        //Do nothing, as in A.java, this code is necessary to be able to override the method.
    }

    public static void main(String[] arguments) { // Sample main method for implementation
        C c = new C(); // Instantiating class C
        int test = 0; // Initializing two integer variables and one String variable
        int test2 = 0;
        String test3 = "";
        c.getNum(test); // takes one integer, using getNum() from A.java
        c.getNum(test, test2); // takes two integers, using getNum() from B.java
        c.getNum(test, test3); // takes an integer and a String, using getNum() from C.java
    }
}

Output:

4
3

As seen in the code above, the argument lists define which version of the method is used. As a side tip, the definition getNum(int a) is no different from getNum(int b), so this would result in it not compiling.

Upvotes: 2

Deepak Bhatia
Deepak Bhatia

Reputation: 6276

The explanation by Pshemo is perfectly right that you can not reduce visibility of overridden or the interface functions.
Lets take an exapmle

 class B 
 {
    protected void getProtected1() 
    {
        System.out.println("4");
    }

    protected void getProtected2() 
    {
        System.out.println("4");
    }

    public void getPublic1() 
    {
        System.out.println("4");
    }

    public void getPublic2() 
    {
        System.out.println("4");
    }

}

class C extends B
{
    @Override
    private void getPublic1() //COMPILATION ERROR : Cannot reduce the visibility of the inherited method from myzeromqApp.B
    {
        System.out.println("3");
    }

    @Override
    protected void getPublic2() //COMPILATION ERROR :Cannot reduce the visibility of the inherited method from myzeromqApp.B
    {
        System.out.println("3");
    }

    @Override
    private void getProtected1() //COMPILATION ERROR : Cannot reduce the visibility of the inherited method from myzeromqApp.B
    {
        System.out.println("3");
    }

    @Override
    public void getProtected2() // NO ERROR IT MEANS YOU ARE ALLOWED TO INCREASE THE VISIBILITY
    {
        System.out.println("3");
    }       
}

From the above example it is clear that you are not allowed to decrease the visibility of function in any case.

In your question you are trying to implement the interface function and we know interface in Java has rules that,

  • Method: only public & abstract are permitted
  • Field: (Variables) only public, static & final are permitted

As thumb of rule, you can never decrease the visibility, of overridden or implemented methods or variables and for interface it is always public (if visibility is concerned) so those should always be public in implemented classes.

Upvotes: 2

user2368558
user2368558

Reputation: 81

A java class file can have only one public class or interface. Change the visibility of the interface and the defined class to default level or declare it in separate files.

Only public and abstract modifiers can be applied to interface methods. The class implementing the interface cannot change the visibility of the method (we cannot change it from public to protected).

Upvotes: 1

Lakshmi
Lakshmi

Reputation: 2294

In order to get this working you can do something like this since there can be only one public class per file and the file name should be the same name as that of the class

public class HelloWorld{

     public static void main(String []args){
        C obj=new C();
        obj.getNum();
     }
}
//interface
interface A {
    public void getNum();
}

 class B {
    protected void getNum() {
        System.out.println("4");
    }
}

 class C extends B implements A {
    public void getNum() {
        System.out.println("3");
    }
}

output: 3

Upvotes: 1

Aniket Thakur
Aniket Thakur

Reputation: 68935

When you implement an interface you need to compulsorily override it to provide concrete implementation of function(unless the class implementing the interface is abstract). In your case you are implementing an interface which make you implement getNum() function and due to overriding class you have another function with same signature which is not allowed. So you get compilation error.

Possible solution : You can make B as an interface.

Upvotes: 5

michali
michali

Reputation: 431

Fix the typos and try again ;)

public interface A {
    public void getNum();
}

public class B {
    protected void getNum() {
        System.out.println("4");
    }
}

public class C extends B implements A {
    public void getNum() {
        System.out.println("3");
    }
}

Upvotes: 6

Related Questions