Java - Defecto con los métodos constructores heredados

 
Vista:

Defecto con los métodos constructores heredados

Publicado por Levir (1 intervención) el 15/03/2021 02:24:09
Hola, tenia un pequeño problema con respecto al tema de la Herencia y los Constructores.

Para resumir presentare una versión simplificada de mi problema y no los aburriré con el código que estaba manejando en ese momento.

Básicamente tenia dos Clases, una de ellas Heredaba de la Otra.
Y la Clase Hija sobrescribía uno de los métodos de la Clase Padre.

El problema es que los constructores de la Clase Hija por razones que yo desconozco al llamar a los constructores de la Clase Padre estos utilizaban el método sobrescrito en lugar del propio de este.

Para ponerlos en contexto básicamente algo como esto:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
public class Persona
{
    private String nombre;
 
    public Persona()
    {
        nombre = "desconocido";
    }
 
    public Persona(String nombre)
    {
        setNombre(nombre);
    }
 
    public void setNombre(String nombre)
    {
        this.nombre = nombre;
        System.out.println("¡Nombre cambiado exitosamente por la Clase Persona!");
    }
}
 
public class Estudiante extends Persona
{
    public Estudiante()
    {
        super();
    }
 
    public Estudiante(String nombre)
    {
        super(nombre);
    }
 
    public void setNombre(String nombre)
    {
        super.setNombre(nombre); // Llama al metodo setNombre() de la Clase Padre
        System.out.println("¡Nombre cambiado exitosamente por la Clase Estudiante!");
    }
}

Y tomando de ejemplo este simple código, el problema surge al crear un objeto Estudiante con el constructor que pide como parámetro un String, ya que en lugar de simplemente imprimirse en pantalla: ¡Nombre cambiado exitosamente por la Clase Persona!

Se imprime: ¡Nombre cambiado exitosamente por la Clase Persona!
¡Nombre cambiado exitosamente por la Clase Estudiante!

Mostrando que esta usando el método sobrescrito.

Entonces quisiera saber como evitar esto, ya que en el código que estaba manejando causaba estragos mucho más grandes.

Básicamente la única solución que conozco es simplemente cambiar el nombre del método y así no sobrescribirlo y que no ocurra ninguna confusión en el constructor.

Pero quisiera saber si existe otra solución mejor que mantenga la sobreescritura o al menos comprender si esto fue creado intencionalmente así.
Valora esta pregunta
Me gusta: Está pregunta es útil y esta claraNo me gusta: Está pregunta no esta clara o no es útil
0
Responder
Imágen de perfil de Rodrigo
Val: 2.041
Plata
Ha mantenido su posición en Java (en relación al último mes)
Gráfica de Java

Defecto con los métodos constructores heredados

Publicado por Rodrigo (623 intervenciones) el 15/03/2021 02:46:38
No entiendo por que sobreescribes el metodo setNombre si no quieres que funcione como esta funcionando.
Si tu constructor indica que hay que invocar el metodo setNombre y lo has sobreescrito en la clase derivada, es ese metodo el que tiene que invocarse.

Por otro lado, tu implementacion indica, en la clase derivada, que tiene que partir haciendo lo que se hacia en la clase base y luego hacer algo especifico, y es exactamente lo que ocurre.
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar
Imágen de perfil de Kabuto
Val: 3.428
Oro
Ha mantenido su posición en Java (en relación al último mes)
Gráfica de Java

Defecto con los métodos constructores heredados

Publicado por Kabuto (1381 intervenciones) el 15/03/2021 11:59:40
El problema, o parte del problema, es que tu constructor de Persona siempre llama al setter.

1
2
3
4
5
6
7
8
9
10
public Persona(String nombre)
    {
        setNombre(nombre);
    }
 
    public void setNombre(String nombre)
    {
        this.nombre = nombre;
        System.out.println("¡Nombre cambiado exitosamente por la Clase Persona!");
    }

Es decir, si creas un objeto Persona:
1
Persona per = new Persona("Juan");

Automáticamente saldrá el mensaje de "nombre cambiado", a pesar de que aún no se ha ordenado cambiar ningún nombre.
Y este "problema", lo hereda la clase Estudiante. Si creas un objeto Estudiante, también saldrá el mensaje de "nombre cambiado por Persona"

Cámbialo para que el constructor no llame al setter, simplemente haga la asignación y listo.

1
2
3
4
5
6
7
8
9
10
public Persona(String nombre)
    {
        this.nombre = nombre;
    }
 
    public void setNombre(String nombre)
    {
        this.nombre = nombre;
        System.out.println("¡Nombre cambiado exitosamente por la Clase Persona!");
    }

El siguiente problema, es que el setNombre de Estudiante, llama al setNombre de Persona:
1
2
3
4
5
public void setNombre(String nombre)
    {
        super.setNombre(nombre); // Llama al metodo setNombre() de la Clase Padre
        System.out.println("¡Nombre cambiado exitosamente por la Clase Estudiante!");
    }


Por tanto, cuando Estudiante cambia un nombre mediante el setter, también lo está cambiando Persona y por eso salen los dos mensajes de "nombre cambiado" de ambas clases.

¿Cómo evitarlo?
Hay que conseguir que el setNombre() de Estudiante, no tenga que llamar al setNombre() de su superclase Persona.
Se podría hacer que Estudiante haga la asignación directamente al atributo nombre:

1
2
3
4
5
public void setNombre(String nombre)
        {
            this.nombre = nombre; 
            System.out.println("¡Nombre cambiado exitosamente por la Clase Estudiante!");
        }

Pero claro, Estudiante no puede acceder directamente al atributo "nombre", porque está declarado como private en la superclase Persona.

Se podría cambiar ese atributo a public, pero esto rompe la filosofía de "encapsulamiento" y el atributo "nombre" sería de libre acceso y se podría alterar su valor sin tener que utilizar los setter.

Sin embargo, entre public y private, hay un nivel intermedio: protected

Si declaramos el atributo como protected:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class Persona {
 
        protected String nombre;
 
        public Persona()
        {
            nombre = "desconocido";
        }
 
        public Persona(String nombre)
        {
            this.nombre = nombre;
        }
 
        public void setNombre(String nombre)
        {
            this.nombre = nombre;
            System.out.println("¡Nombre cambiado exitosamente por la Clase Persona!");
        }
    }


Esto hace que el atributo sea accesible para las clases hijas que vayan a heredar de Persona, pero solo ellas. El atributo permanecerá "encapsulado" y con el acceso restringido para cualquier otra clase que no sea hija de Persona.

De este modo, ahora Estudiante si puede asignar un nuevo valor al atributo "nombre", sin tener que llamar al setter de la superclase


En este editor online, se puede ejecutar un pequeño ejemplo con estos cambios: https://www.online-ide.com/CEh5TaixsZ
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar