5

Consider the following classes:

class A {
    void print() {
        System.out.println("A");
    }
}

class B extends A implements C {
}

public interface C {
    void print();

}

I get this error:

The inherited method A.print() cannot hide the public abstract method in C

Now, I understand that print() must be public in order the eliminate the compilation error, but what's the reason behind this?

AngryOliver
  • 357
  • 1
  • 3
  • 15

6 Answers6

6

The answer is simple interface methods are always public or else just use composition instead of inheritance. Also to note that while overriding a method you can not narrow down the access level of the method.

The Oracle Docs says:

The access modifier public (§6.6) pertains to every kind of interface declaration.

Rahul Tripathi
  • 152,732
  • 28
  • 233
  • 299
5

B#print can never be truly private, because anyone can call it via the interface:

B b = new B();
C c = b;
c.print();

Java doesn't let you pretend it's private when it is effectively public. (C++ does; different languages make different trade-offs.)

Alan Stokes
  • 18,320
  • 3
  • 41
  • 63
  • It's not about pretending. One aspect is controlling the way how the method is accessed, because in some cases this is an important aspect. – JensG Jul 04 '14 at 20:50
4

The method void print() in class A is implementation for the interface method declaration. Now , in the interface C this method is public ( every interface method is public by default ) and the rules of OOP ( Liskov principle in particular ) dictates that the visibility of this method's implementation in class A cannot be lower than that in its interface - hence it has to be public.

Bhaskar
  • 7,063
  • 5
  • 33
  • 50
  • 2
    I'm surprised noone else mentioned Liskov substitution principle. It is the core reason why defining private methods in interfaces doesn't make any sense, and why narrowing access modifier from a derived class isn't permissible. – Lie Ryan Jul 04 '14 at 21:35
2

Short answer is because Java doesn't allow it. According to the Java Language Specification under 9.1.1. Interface Modifiers - JLS-9.1.1,

The access modifier public (§6.6) pertains to every kind of interface declaration.

The access modifiers protected and private pertain only to member interfaces within a directly enclosing class or enum declaration (§8.5.1).

So if you don't specify an access modifier in your non-member interface (like void print()) it is public and your class which implements that interface must provide a public void print().

Community
  • 1
  • 1
Elliott Frisch
  • 183,598
  • 16
  • 131
  • 226
  • 1
    IOW, it must be public *only* because the spec. says so? – JensG Jul 04 '14 at 20:48
  • @JensG If by spec you mean the Java Language Specification then yes, because every implementation of Java is supposed to behave according to said specification. – Elliott Frisch Jul 04 '14 at 20:49
  • So there is no other, say technical, reason? – JensG Jul 04 '14 at 20:51
  • @JensG You mean besides how would a caller call it if it were otherwise? – Elliott Frisch Jul 04 '14 at 20:51
  • Well, I can call a protected interface method. I can't just do it in Java, because the bible forbids it :-) – JensG Jul 04 '14 at 20:53
  • 1
    @ElliottFrisch I think that is the only reason. I don't see why the specs could not have allowed protected, package private, or even private interface methods. – emory Jul 04 '14 at 20:53
  • @emory A private interface method could never be called, surely? – Alan Stokes Jul 04 '14 at 21:24
  • @AlanStokes I think if an interface with private methods was nested inside another class, then its private methods could be called from anywhere within that other class. Alternatively, you could nest classes within a top level interface that call the private methods of that interface. – emory Jul 04 '14 at 21:32
1

Well, think it this way: if an interface defined private methods then these methods would only be called by the class implementing the interface, and that doesn't make much sense, since (in Java) an interface defines the contracts between classes. When a class follows an interface then the methods defined in the interface can be called in the implementation by external classes.

In your case, your class B is extending A while class A is not implementing the interface C. So, by extending A it inherits a method that has less access than the one defined in the interface, and that is not allowed.

If your class A had implemented the interface you would have seen the error "Cannot reduce the visibility of the inherited method from C"

Alexandre Santos
  • 7,654
  • 7
  • 35
  • 60
  • 1
    If an interface defined private methods, then these methods would only be visible to any class within the same class as the interface. `class TopLevel { interface Iface { private void dostuff();} class Impl implements IFace { private void doStuff(){}} class User { /* I can call doStuff */ } }` – emory Jul 04 '14 at 20:56
  • interfaces are not allowed to define private methods. I was just speculating that if they were allowed to define private methods, visibility would work differently than you are saying. My code snippet should not compile. – emory Jul 04 '14 at 21:23
  • Ah, you were agreeing with me. Thanks. +1 for your comment. – Alexandre Santos Jul 04 '14 at 21:24
1

All the methods in an interface are implicitly public. The names and return types of the methods(the ones B inherits from A and C) are same in your case but the visibility modifiers are different. And if you change the visibility modifier of an inherited method the compiler will complain because you cannot reduce the visibility of an inherited member.

Juvanis
  • 25,000
  • 3
  • 61
  • 84