Java - Hiding Overriding and the modifier final
Asked Answered
D

2

5

I couldn't find a question like mine, so I hope it's not a duplicate one.

Again it's about overriding and hiding. I think - but I might be wrong - I understood both.

The following code behaves as expected, both methods have been hidden. method1 because it is a private method and private methods can't be overridden only hidden, method2 because it's static and static methods can't be overridden, they can only be hidden.

public class Child extends Parent { 
    public void method1(){System.out.println("child");}     
    public static void method2(){ System.out.println("static child");}  
}

class Parent{
    private void method1(){ System.out.println("parent");}      
    public static void method2(){ System.out.println("static parent");}

    public static void main(String[] args){
            Parent p = new Child();
            p.method1(); //prints out "parent"
            p.method2(); //prints out "static parent"
    }
}

If I read the specs it says:

http://docs.oracle.com/javase/specs/jls/se8/html/jls-8.html#jls-8.4.3.3

A method can be declared final to prevent subclasses from overriding or hiding it.

If I change method1 in the Parent class to "final"

private final void method1(){ System.out.println("parent");}

Everything works fine. edit start: I expected an compiler error saying that final methods can't be hidden, but that didn't happen. :edit end

Question no 1: does that mean only static methods can be hidden? In the book I'm reading (OCA study guide, Jeanne Boyarsky and Scott Selikoff page 252) they clearly say that a private method was hidden.

Then I changed method2 in the Parent class to

public final static void method2(){ System.out.println("static parent");}

Now the compiler does complain, the error says "Child cannot override method2()" which is pretty confusing because I thought I tried to hide a method.

Question no 2: Shouldn't it be "Child cannot hide method2()"?

edit start: I am well aware that no overriding happens here, but as the mentioned specs point out: the modifier final prevents methods to be overridden or hidden, that's why I put it in the title. :edit end

Disputant answered 3/2, 2016 at 13:56 Comment(5)
Your example is a bit confusing, because method2 is defined before method1. For readability you may want to restructure to: a) first define method1, then metho2 and b) first define class Parent, then class Child and finally some public class containing the main method as a test frame.Foe
And now my real question: What do you mean by "Everything works fine"? Please state what you expected and what happend. I would expect a compiler error when Overriding a final method - did you get that error? Or did the compiler go through with it? Did you see the printout of the overriden method?Foe
Oracle tutorial strongly implies you can't override static method, only hide it: docs.oracle.com/javase/tutorial/java/IandI/override.htmlDoubledecker
@penguineer: I changed the order of the methods, but I kept the order of the classes. I wouldn't have been helpful to make a public class containing the main method as the method1 in the parent class is private. To test the final modifier I needed to construct it that way.Disputant
@Victor Sorokin/penguineer: There is no overriding happening here. I edited my posting to mention that.Disputant
E
8

Question 1

Question no 1: does that mean only static methods can be hidden?

Parent.method1() was not visible in nor inherited by Child simply by virtue of being private. So Child.method1() didn't override or hide Parent.method1(), it merely created a new method in Child that had the same name, parameters and return type.

See http://docs.oracle.com/javase/specs/jls/se8/html/jls-8.html#jls-8.4.8.3:

Note that a private method cannot be hidden or overridden in the technical sense of those terms. This means that a subclass can declare a method with the same signature as a private method in one of its superclasses, and there is no requirement that the return type or throws clause of such a method bear any relationship to those of the private method in the superclass.

Question 2

Question no 2: Shouldn't it be "Child cannot hide method2()"?

Yes, you are correct. It should be "hide". Per the JLS (http://docs.oracle.com/javase/specs/jls/se8/html/jls-8.html#jls-8.4.8.2),

If a class C declares or inherits a static method m, then m is said to hide any method m', where the signature of m is a subsignature (§8.4.2) of the signature of m', in the superclasses and superinterfaces of C that would otherwise be accessible to code in C.

"Hiding" is what static methods do to static methods. "Overriding" is what instance methods do to instance methods. The two can't be mixed: a static method can't override or hide an instance method, and an instance method can't override or hide a static method.

BTW, my Eclipse compiler gives a similar error message: "Cannot override the final method from Parent"

Erosive answered 3/2, 2016 at 14:13 Comment(2)
private methods and hiding: I read this in the mentioned book, that a private method was hidden and because of the behaviour of the compiler I thought it can't be hidden (because of the specs about the final modifier and hidden methods). I didn't find the part (8.4.8.3) about private methods though. Thanks, that sheds some light on the whole thing.Disputant
P.S. Eclipse compiler: I know, I tested the whole thing in the console and eclipse. Same error.Disputant
R
2

Well, I'm quite new to java, but I'll try to answer.

The difference resides in the fact that you're using different access level modifiers: you're using private on method1() of Parent class and public on method1() on Child class. In fact, you're not hiding the method as it is not the same method. The private modifier specifies that the member can only be accessed in its own class, therefore, you're using a new method when you declare method1() on Child class. Even though, child inherits all methods from Parent (as it extends it), private methods are not inherited. In the case of method2(), as it is declared public, it is inherited by Child class and can be hidden.

More about it (Taken from oracle tutorials):

Private Members in a Superclass

A subclass does not inherit the private members of its parent class. However, if the superclass has public or protected methods for accessing its private fields, these can also be used by the subclass.

A nested class has access to all the private members of its enclosing class—both fields and methods. Therefore, a public or protected nested class inherited by a subclass has indirect access to all of the private members of the superclass.

EDITED: Question 2:

You hide a static method, not a final one. Only static ones can be hidden as in here:

class SuperClass {
    static void display() {
        System.out.println("Super");
    }
}

class SubClass extends SuperClass {
    static void display() {
        System.out.println("Sub");
    }
}

public class Test {
    public static void main(String[] args) {
        // Prints "Super" in console
        SuperClass sup = new SubClass();
        sup.display();

        // Prints "Sub" in console
        SubClass sub = new SubClass();
        sub.display();
    }
}

You use the final keyword in a method declaration to indicate that the method cannot be overridden by subclasses. So, if you change it, you are overriding it and, therefore, compiler says:

overridden method is static,final (notice the final).

Compiler complains about it because you're not longer hiding it. As you declared it final, you're overriding it. It will give you the same error, if you do not use the static modifier on the Child class as you'll be trying to override what it is no longer static. Hiding is only used when the static method hides another static method. If you try:

  1. nonstatic method "hides" static one: that is override.
  2. final method "hides" static one: that is override.

In those cases, you're not trying to hide anymore (because hiding is use only on static) but you're trying to override.

Roumell answered 3/2, 2016 at 14:28 Comment(2)
Exactly. I was talking about the compiler, though. If you try: instance method "hides" static one, the complier will think that you're trying to override it because you can only hide static methods. That is why the compiler does not say ´hidden method is static,final´. You see, compiler only knows that static can hide static. If you try to change static in any other way other than ´static hiding static´, compiler will think you're overriding it. There is no ´hidden method is static,final´ error because hiding only occur on static context, as far as I think. :)Roumell
Oh, my bad. I was talking in a hypothetical way. I was saying: Hypothetically, suppose that you write: instance method "hides" static one. Thanks :)Roumell

© 2022 - 2024 — McMap. All rights reserved.