[SOLUCIONADO] Llamar métodos no estáticos/final desde constructores - JAVA

Iniciado por phr4ckl0t, Agosto 19, 2017, 05:28:32 PM

Tema anterior - Siguiente tema

0 Miembros y 1 Visitante están viendo este tema.

Saludos muchachos, tiempo sin pasar por aquí espero estén bien.
El día de hoy me ha surgido una pregunta con base a una frase que he leido en un libro de "Como programar en Java 10ma edición" de Deitel y Deitel, donde argumentan que no se deben implementar metodos sobreescribibles en los constructores de clase, ya que se pueden generar resultados indeseados. El punto es que si tengo una superclase cuyo constructor utiliza un metodo de instancia para validar un atributo a la hora de inicializarlo, y sobreescribo ese metodo en la subclase, el constructor de la subclase hará la llamada al constructor de la superclase, el cual usará la version sobreescrita del metodo que implementa en su cuerpo, se me ha dado por probarlo pero los resultados no son los que esperaba, de seguro no me ha quedado clara la idea, no haciendo mas esto fué lo que probé.
Código: java
public class B{
    private int a;

    public B(int a){
        setA(a);
    }

    public int getA(){
        return a;
    }

    public void setA(int a){
        this.a = 0;
    }
}


Código: java
public class A extends B{

    private int a;

    public static void main(String[] args){
        A a  = new A(5);
        System.out.println(a.getA());
    }

    public A(int a){
        super(a);
    }

    @Override
    public void setA(int a){
        this.a = 1;
    }
}


La idea era que al pasarle un argumento al constructor a la hora de instanciar a la clase A, este tomara la version sobreescrita del metodo setA() y me inicializara el atributo "a" con valor de 1, pero veo que está tomando la version de la superclase e inicializa el valor de "a" en 0, por lo que no se refleja lo que dice el libro, la verdad quiero saber como manejar esto para tener los conceptos claros, y digerir esta gota en el mar del conocimiento. Gracias de antemano.

Agosto 19, 2017, 09:08:16 PM #1 Ultima modificación: Agosto 19, 2017, 09:14:48 PM por grep
No tienes permitido ver los links. Registrarse o Entrar a mi cuenta
...pero veo que está tomando la version de la superclase e inicializa el valor de "a" en 0, por lo que no se refleja lo que dice el libro...

Este resultado es correcto porque tienes dos private int a; diferentes (por ser privados, uno es solamente visible para la clase B y el otro es solamente visible para la clase A). Ya sea que llames a getA() desde una instancia de A o desde una instancia de B, getA() va a devolver el valor 0.

Dicho de otra forma:

Código: java

public class B{
...
public B(int a){
    setA(a);
}
...
}


efectivamente llama a:

Código: java
public class A extends B {
...
    @Override
    public void setA(int a){
        this.a = 1;
    }
...
}


el problema es que this.a = 1; asigna el valor a la variable privada de A, no a la variable privada de B.

Para que el prorgama funcione como esperas debes utilizar el keyword protected y declarar la variable solamente en la superclase.

CODIGO CORREGIDO:
Código: java

public class B{
    // private int a;
    protected int a;

    public B(int a){
        setA(a);
    }

    public int getA(){
        return a;
    }

    public void setA(int a){
        this.a = 0;
    }
}

Código: java

public class A extends B{
    // private int a;

    public static void main(String[] args){
        A a  = new A(5);
        System.out.println(a.getA());
    }

    public A(int a){
        super(a);
    }

    @Override
    public void setA(int a){
        this.a = 1;
    }
}

Saludos

Entonces basandome en tu aclaración, puedo decir que el problema me lo está generando el método getA(), ya que al ser "a" private el toma la variable private de B mas no la de A y por eso arroja el resultado especificado, para obtener el a = 1 entonces debo sobreescribir el método para que tome la variable private de A, o en su defecto declarar "a" como protected y solo en la superclase, aunque esto debilitaria el encapsulamiento, pero bueno el punto era entender el concepto y me lo has dejado bien en claro, mil gracias por tu tiempo y tu aporte  ;D ;D

La encapsulación es una forma de proteger contenido y es un concepto que hay que tener claro en programación ¿Cómo encapsulamos? pues con los modificadores de acceso.

Público (modificador public ), en cuyo caso la clase era visible a cualquier otra clase (cualquier otro
fragmento de código del programa).
Privada al paquete (sin modificador o modificador "por omisión"). En este caso, la clase sólo será
visible a las demás clases del mismo paquete, pero no al resto del código del programa (otros
paquetes).
En el caso de los miembros, disponías de otras dos posibilidades más de niveles de accesibilidad, teniendo
un total de cuatro opciones a la hora de definir el control de acceso al miembro:
Público (modificador public ), igual que en el caso global de la clase y con el mismo significado
(miembro visible desde cualquier parte del código).
Privado al paquete (sin modificador), también con el mismo significado que en el caso de la clase
(miembro visible sólo desde clases del mismo paquete, ni siquiera será visible desde una subclase
salvo si ésta está en el mismo paquete).
Privado (modificador private ), donde sólo la propia clase tiene acceso al miembro.
Protegido (modificador protected )

Para resumirtelo:
Si tú pones un atributo o método privado sólo puede ser accedido desde métodos de la misma clase
Si pones un atributo publico public puede ser accedido desde cualquier sitio dentro del package y fuera de él
Si pones un atributo protected sólo será accedido desde la propia clase y clase hijas o herederas

Lo que te están indicando  es que al hacer el método privado de la clase Padre no es accesible de la Clase Hija aunque herede de su padre para eso tendrían que ser atributos protected

Espero haberte aclarado el asunto Suerte y al Toro
No tienes permitido ver los links. Registrarse o Entrar a mi cuenta

Claro que si Hu3c0, muchas gracias a ti también ya me queda resuelta la duda  ;D

No tienes permitido ver los links. Registrarse o Entrar a mi cuenta
...entonces debo sobreescribir el método para que tome la variable private de A, o en su defecto declarar "a" como protected y solo en la superclase, aunque esto debilitaria el encapsulamiento...

Ciertamente debilita el encapsulamiento. Una regla general en OOP (Object Oriented Programming) es hacer todo tan privado como sea posible. Vas a encontrar muy buenas respuestas en No tienes permitido ver los links. Registrarse o Entrar a mi cuenta pregunta hecha en StackOverflow.

La mejor alternativa es declarar la variable private int a; solamente en la superclase B y llamar al metodo setA() de la superclase B desde el metodo setA() de la subclase A.

Código: java

public class B{
    private int a;

    public B(int a){
        setA(a);
    }

    public int getA(){
        return a;
    }

    public void setA(int a){
        // this.a = 0;
        this.a = a;
    }
}


Código: java

public class A extends B{
    // private int a;

    public static void main(String[] args){
        A a  = new A(5);
        System.out.println(a.getA());
    }

    public A(int a){
        super(a);
    }

    @Override
    public void setA(int a){
        // this.a = 1;
        super.setA(1);
    }
}


Saludos

Correcto mi estimado grep así mismo es, aunque ya ahí estaría demás hacer un @No tienes permitido ver los links. Registrarse o Entrar a mi cuenta ya que se puede trabajar directamente con el método heredado.
Muchas gracias por todo.