0

I have been working on this code and I am not able to figure out why certain access modifiers work and some do not:

public class Base {
  protected int method(int x) { return 0; }
}

class Child extends Base {
  // Line 1: Compiles
  public int method(int x) { return 0; }

  // Line 2: Cannot reduce the visibility of the inherited method from Base
  private int method(int x) { return 0; }

  // Line 3: Compiles
  private int method(long x) { return 0; }

  // Line 4: The return type is incompatible with Base.method(int)
  protected long method(int x) { return 0; }

  // Line 5: Compiles
  protected int method(long x) { return 0; }

  // Line 6: Compiles
  protected long method(long x) { return 0; }

  // Line 7: Compiles
  protected long method(int x, int y) { return 0; }
}

I am trying to understand why lines 1, 3, 5, 6, and 7 are allowed but lines 2 & 4 are not.

I've tried searching but haven't found a clear explanation, though I did find In Java, difference between default, public, protected, and private

Community
  • 1
  • 1
  • There's a lot of concepts here. I'm voting to close for too broad. But look into [reducing visibility](http://stackoverflow.com/questions/6851612/java-access-modifiers-and-overriding-methods), method overloading, and return type compatibility. – Sotirios Delimanolis Jun 19 '14 at 23:39
  • This is a great example of the benefit of annotating your methods with [`@Override`](http://docs.oracle.com/javase/tutorial/java/annotations/predefined.html) - the compiler will confirm for you that the method you're annotating actually overrides a parent method. Being explicit about the behavior you expect will greatly reduce this sort of confusion as you're developing. – dimo414 Jun 20 '14 at 02:18
  • See http://stackoverflow.com/questions/4041157/java-cannot-reduce-the-visibility-of-the-inherited-method-from-object – Raedwald Jun 20 '14 at 04:34

3 Answers3

1

The methods taking a long or 2 ints as an argument (3,5,6,7) are not overriding the Blip method as the method signatures (combination of name and parameters) are different.

Line 1 is fine because it increases the visibility of the method. Inversely, line 2 is failing because it decreases the visibility of the method.

Line 4 is not working because the return value is different, and not in a more specific way. When returning primitives, the return value cannot change. However, when returning Objects, it is possible for subclasses to return a more specific class. For example, Cloneable.clone() returns an Object. Actual implementations are free to change that to return any type of Object.

Brett Okken
  • 6,210
  • 1
  • 19
  • 25
  • Return types are not a part of a method's signature. See: http://docs.oracle.com/javase/tutorial/java/javaOO/methods.html second last line. – aa333 Jun 19 '14 at 23:56
  • They kind of are. If you change the return type of a method you will have made a binary non-passive change, even changing from `Collection` to `List` or `Set`. I admit it needs to be quite the nuanced description that I was lazy about. – Brett Okken Jun 20 '14 at 00:00
0

First off, I think your notes are not entirely correct.

Apart from access modifiers, the concept of method overloading is also in play here.

Method Overloading allows you to define multiple methods in the same class with the same name if they have different signatures i.e. different number or types of parameters.

Remember return types are not part of a method's signature.(There are certain compatibility quirks with this which I leave for you to figure out from the language documentation)

http://docs.oracle.com/javase/tutorial/java/javaOO/methods.html

So in this case:

1 works: because it's the first implementation of the method named blipvert.
2 doesn't work: because a public method with the same signature has already been defined.
3 works: An overloading of method defined in 1 with different parameter type.
4 doesn't work: for the same reason as 2, a wider access method is already defined.
5 doesn't work: because a public method with the same signature is already defined.
6 doesn't work: because a public method with the same signature is already defined.
7 works: Overloading with different number of parameters.

Test it out on a compiler. I did on Javac 1.7.0_09 at compileonline. Unless you comment everything except 1,3 and 7 it won't compile.

aa333
  • 2,556
  • 16
  • 23
0

Signature is bound at compile-time contains: class, method name and parameters

That means that, you can't have two same signatures like:

  • Vert.blipvert(int) //coming from inharitance which returns int
  • Vert.blipvert(int) //which returns long

and also you can't have:

  • Vert.blipvert(int) //coming from inharitance which is proteced
  • Vert.blipvert(int) //which is private

You probably wonder, why it doesn't override method? Normaly it does, but inheritance means that all methodes defined in parent can also be used in chlid.

Note: Normaly signature would give full class names with packages, not just partial, but imho writing it like that, would look overcomplicated.

KonradOliwer
  • 166
  • 6