Doubt about access modifiers and polymorphism

Asked

Viewed 135 times

2

I have a very beginner question about polymorphism/access modifiers in Java.

I’d like to find out why a certain phenomenon occurs in my code. Below is an example of classes:

Class Pai:

public class Pai {
    public void metodo1() { //private dá problema
        System.out.println("Metodo 01 Pai");
    };

    public void metodo2() {
        metodo1();
    }
}

Class that inherits the previous class:

public class Filha extends Pai{

    public Filha() {
    }

    public void metodo1() {
        System.out.println("Metodo 01 Filha");
    }   
}

And class Main:

public class Main {
    public static void main(String  args[]) {
        Pai instancia = new Filha();
        instancia.metodo2();

    }
}

The println of Main is "Metodo 01 Filha". However, by changing the metodo1() class Pai for private, the return of the method main becomes "Metodo 01 Pai". I would like to understand why this change occurs.

2 answers

2

Overlapping methods allow subclass to replace some of the methods that she sees in the superclass.

If the superclass method is public or protected, then the subclass sees it, and when declaring a method with the same signature the overlap occurs. When overlapping occurs, when calling the superclass method in a subclass instance, the called method will be the one that has been overwritten.

However, when the superclass method is private, it is hidden from the subclass, and therefore there is no overlap, because the subclass does not see it. It occurs that only two methods have the same name but operate unrelated between them. Thus, if the private superclass method is called, the subclass method is not invoked.

Finally, in the case of package visibility, the subclass overrides the superclass method only if it is in the same package.

It is recommended to use the annotation @Override in subclass methods that intend to overwrite those of the superclass to avoid cases like this. Thus, if the subclass wants to overwrite a superclass method, but fails, the result is a compilation error, rather than a confusion that only manifests itself in execution. This also mitigates the problem of the superclass method being renamed or in some other way having its signature altered leaving broken the subclass method that should overwrite it.

1

The private members of the superclass cannot be replaced (or even observed) by the child classes. Therefore, the method to be considered is that of the subclass Filha.

Only members with access modifier protected or public can be inherited and replaced by subclasses.

Of documentation:

Members of a class that are declared private are not inherited by subclasses of that class. Only Members of a class that are declared protected or public are inherited by subclasses declared in a package other than the one in which the class is declared.

As you can see in victor’s response, make the intention explicit, using the annotation @Override:

public class Pai {
    public void digaOla() {
        System.out.println("Olá");
    }
}

public class Filha extends Pai {
    @Override
    public void digaOla() {
        System.out.println("Oi");
    }
}

This annotation is for both the compiler and who will read your code. I have commented on this in other answers here on the site. Keep in mind that:

  • Explicit is better than implicit. Make your goals clear to anyone who reads the code. This reader may be a co-worker, a unknown on Github and even you in a few months trying understand what is written. Read the PEP 20, is applicable here also.
  • Typo. Imagine you want to overlap Object.toString() and write tostring(). Without the note everything goes occur well, but with the annotation would give a compilation error because it does not exists Object.tostring(). A worse case would be with the hashCode().

In languages like C#, it is mandatory to denote intent using the modifier override.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.