Underc0de - La Casa de los Informáticos

Foros Generales => Dudas y pedidos generales => Mensaje iniciado por: phr4ckl0t en Agosto 19, 2017, 05:28:32 PM

Título: [SOLUCIONADO] Llamar métodos no estáticos/final desde constructores - JAVA
Publicado por: phr4ckl0t en Agosto 19, 2017, 05:28:32 PM
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) [Seleccionar]
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) [Seleccionar]
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.
Título: Re:llamar métodos no estáticos/final desde constructores - JAVA
Publicado por: grep en Agosto 19, 2017, 09:08:16 PM
You are not allowed to view links. You are not allowed to view links. Register or Login or You are not allowed to view links. Register or Login
...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) [Seleccionar]

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


efectivamente llama a:

Código (java) [Seleccionar]
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) [Seleccionar]

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) [Seleccionar]

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
Título: Re:llamar métodos no estáticos/final desde constructores - JAVA
Publicado por: phr4ckl0t en Agosto 20, 2017, 12:27:40 PM
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
Título: Re:llamar métodos no estáticos/final desde constructores - JAVA
Publicado por: Hu3c0 en Agosto 20, 2017, 04:07:32 PM
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
Título: Re:llamar métodos no estáticos/final desde constructores - JAVA
Publicado por: phr4ckl0t en Agosto 20, 2017, 07:39:49 PM
Claro que si Hu3c0, muchas gracias a ti también ya me queda resuelta la duda  ;D
Título: Re:llamar métodos no estáticos/final desde constructores - JAVA
Publicado por: grep en Agosto 20, 2017, 09:23:44 PM
You are not allowed to view links. You are not allowed to view links. Register or Login or You are not allowed to view links. Register or Login
...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 esta (http://"https://stackoverflow.com/questions/8353272/private-vs-protected-visibility-good-practice-concern") 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) [Seleccionar]

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) [Seleccionar]

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
Título: Re:llamar métodos no estáticos/final desde constructores - JAVA
Publicado por: phr4ckl0t en Agosto 20, 2017, 11:24:39 PM
Correcto mi estimado grep así mismo es, aunque ya ahí estaría demás hacer un @Override (https://underc0de.org/foro/index.php?action=profile;u=8340) ya que se puede trabajar directamente con el método heredado.
Muchas gracias por todo.