1CFS-PROG-U04-Algumos Ejercicios SOLUCIONADOS (E3-E11)

Descargar como pdf o txt
Descargar como pdf o txt
Está en la página 1de 11

UNIDAD 4. Programación Modular, Clases y Objetos.

EJERCICIOS DEL TEMA

E3. A la clase Empleados del ejercicio E2 queremos cambiar a estático


el método getNombre() ya que hace lo mismo para todos los objetos
(devuelve el nombre del empleado) y en vez de estar en cada objeto
que se almacene una sola vez, algo así:
public static String getNombre() { return this.nombre; }

Analiza la solución propuesta y soluciona el problema.

No puede ser estático (quedarse en la clase) porque cada empleado


tiene su propio nombre. La clase no tiene el dato nombre. Si no hay un
único nombre (cada objeto tiene el suyo), es cada objeto el que debe
devolverlo, es decir, el que debe tener su propio método que lo
devuelva.

Si un método devuelve/usa datos de objetos hay 3 posibilidades:


• No es estático y los datos son del objeto que contiene al
método.
• Los objetos los recibe como parámetros.
• Los crea en su interior: o = new Objeto(); return o.dato;

Además del error de no existir nombre, genera otro error de


compilación, porque en un código estático (de la clase) no tiene sentido
usar this (el objeto actual que ejecuta el código) porque el código
static no es de ningún objeto, es de la clase (y no existirá nunca this
dentro de él): -----> por tanto hay que quitarle el modificador static.

E4. A la clase Empleados del ejercicio E2 queremos añadirle el dato


sueldo y un password común para que lo usen en el departamento de

1/11
UNIDAD 4. Programación Modular, Clases y Objetos.

recursos humanos. Necesitamos poder consultar y modificar todos los


datos de un empleado (salvo los passwords) desde fuera de la clase, y
también modificarlos, pero seguir asegurando que la edad de cada uno
es mayor o igual a 18 y que el sueldo solamente lo podrán
consultar/cambiar si conocen un password común que compartan todos
los objetos. Piensa en una forma de conseguir todo esto.

// Fichero Empleado.java
public class Empleado {
private String nombre;
private int edad;
private double sueldo;
private static passwordComun = "123";

public Empleado(String nombre, int edad)


throws IllegalArgumentException {
if( edad < 18 )
throw new IllegalArgumentException("Edad mínima 18");
this.nombre = nombre;
this.edad = edad;
}

public String getNombre() { return nombre; }

public int getEdad() { return edad; }

public double getEdad(String clave) {


return ( passwordComun.equals( clave ) )? sueldo:0;
}

public void setNombre(String nombre) { this.nombre = nombre; }

public void setEdad(int edad) throws IllegalArgumentException{


if( edad < 18 )
throw new IllegalArgumentException("Edad mínima 18");
this.edad = edad;
}
public void setSueldo(String clave, double sueldo) {
if( passwordComun.equals( clave ) ) {
this.sueldo = sueldo;

2/11
UNIDAD 4. Programación Modular, Clases y Objetos.

}
}
}

E5. Necesitamos una clase para manejar puntos en 2 dimensiones. Cada


punto queda definido por su coordenada x y por su coordenada y.
Creamos la clase con un constructor al que pasamos los dos valores.
Analiza el código y encuentra y soluciona los errores.
// Fichero Punto2D.java
Public class empleado {
public double x, y;

public void Punto2D(double x, double y) {


x = x;
y = y;
}
}

// Fichero PruebaPuntos.java
public class PruebaPuntos {
public static void main(String[] args) {
Punto2D p1 = new Punto2D(3, 2.5);
System.out.println( p1.x, p2.y );
}
}

// Fichero Punto2D.java
public class Punto2D {
public double x, y;

public Punto2D(double x, double y) {


this.x = x;
this.y = y;
}
}

E6. Queremos que al usar el constructor por defecto (sin argumentos)


se cree el punto (0,0). Además preferimos no añadir más sentencias

3/11
UNIDAD 4. Programación Modular, Clases y Objetos.

innecesarias a las que necesitemos. ¿Qué tal te parecen estas


soluciones sabiendo que public Punto2D() { x = 0; y = 0; } está
descartada porque añadimos sentencias?

a) No hacemos nada y cuando se use new Punto2D(); Java usará el


constructor de Object, que crea el objeto e inicializa las
variables miembro x, y a 0 al no ser locales. Razona la respuesta
y luego la confirmas escribiendo código que lo pruebe.

Al definir un constructor propio, perdemos el constructor por


defecto de Object. Si queremos uno, hay que definirlo de forma
explícita de nuevo.

b) public Punto2D Punto2D() { return new Punto2D(0, 0); }

Un constructor no indica el tipo, de hacerlo, deja de ser un


constructor. Una diferencia entre un método normal (tiene tipo)
y un constructor (no tiene tipo) es que a un método normal lo
llamamos cuando queremos, pero a un constructor lo llama
automáticamente new cuando crea un objeto. Si no dejamos el
tipo, no puede devolver nada con return.

c) public Punto2D() { Punto2D this = new Punto2D(0,0); }

Este constructor intenta cambiar el objeto actual (this). Pero


es que dentro del constructor no existe aún, el trabajo del
constructor es acabarlo, hacer que exista con un estado
coherente. No puedes declarar this (indicar su tipo de dato).

Si no te cuadra ninguna de las anteriores, piensa como hacer el


constructor usando el que ya tienes.
public Punto2D() { this(0,0); }

4/11
UNIDAD 4. Programación Modular, Clases y Objetos.

E7. Queremos añadir a la clase Punto2D getters y setters y una


operación suma de forma que reciba de argumento un Punto2D y
devuelva un nuevo Punto2D con la suma de ambos:

(x1, y1) + (x2, y2) = (x1 + x2, y1 + y2)

Crea un método main para probar la clase y completa las siguientes


sentencias hasta conseguir una salida como esta:
Punto2D p1 = new Punto2D(3, 2.5);
Punto2D p2 = new Punto2D(1, -1);
Punto2D p3 = p1.suma( p2 );
System.out.println( /* ... completa ... */ );

// Fichero Punto2D.java
public class Punto2D {
public double x, y;

public Punto2D(double x, double y) {


this.x = x;
this.y = y;
}

public Punto2D() { this(0,0); }

public double getX() { return x; }

public double getY() { return y; }

public void setX(double x) { this.x = x; }

public void setY(double y) { this.y = y; }

5/11
UNIDAD 4. Programación Modular, Clases y Objetos.

public Punto2D suma(Punto2D p) {


Punto2D resul = new Punto2D();
if(p == null) {
resul.x = this.x;
resul.y = this.y;
return resul;
}
resul.x = this.x + p.x;
resul.y = this.y + p.y;
return resul;
}

public static void main(String[] args) {


Punto2D p1 = new Punto2D(3, 2.5);
Punto2D p2 = new Punto2D(1, -1);
Punto2D p3 = p1.suma( p2 );
System.out.println( "(" + p1.x + " , " + p2.y + ") + " +
"(" + p2.x + " , " + p2.y + ") = (" +
p3.x + " , " + p3.y + ")" );
}

E8. Nos damos cuenta que si queremos imprimir muchos puntos, ahora
mismo es un poco tedioso. ¿Cómo conseguir que al pasar un punto se
imprima "(x,y)"? Sabes que Object, como buen padre, presta sus
métodos incluido toString() a todos sus hijos, incluido Punto2D. Por
tanto, cambiamos la última línea del código de prueba anterior por:
System.out.println( p1 + " + " + p2 + " = " + p3 );

Si no obtienes la salida que querías, quizás tengas que sobreescribir


(sustituir, override en inglés) el método toString() de Object.
// Añadir a la clase Punto2D este método
public String toString(){
return "(" + x + ", " + y + ")";
}

6/11
UNIDAD 4. Programación Modular, Clases y Objetos.

E9. Ahora necesitas saber si dos Punto2D son iguales para poder
compararlos:
p2.setX( p1.getX() );
p2.setY( p1.getY() );
System.out.println( p1 + " es igual a " p2 + "? " + (p1 == p2) );

Como son objetos, supongo que a estas alturas ni se te pasará por la


cabeza usar el operador == de arriba (solamente te serviría para saber
si son el mismo objeto, en cuyo caso sí serían iguales).

Sobreescribe el método equals() de Object que permita comparar


Puntos2D con el resto de objetos. (Yo lo voy a hacer mal a posta)
// En el main cambiamos la última línea por:
System.out.println( p1 + " es igual a " + p2 + "? " +
p1.equals( p2) );
// Añadimos a la clase el método (OJO, está mal...)
public boolean equals(Punto2D p) {
return x == p.x && y == p.y;
}

E10. Utiliza la anotación @Override delante del método equals() de


Punto2D para comprobar si has realizado bien la sustitución del
método del padre, o bien si al equivocarte lo que has hecho es
sobrecargar el nombre del método (ligadura dinámica) en vez de
sobreescribirlo. Si lo has sobreescrito mal, debes corregirlo.
Queremos sustituirlo, no sobrecargar el método equals(). Prueba el
método corregido con el código de prueba correcto.
// Añadimos a la clase el método (OJO, está mal...)
@Override
public boolean equals(Punto2D p) {
return x == p.x && y == p.y;
}

7/11
UNIDAD 4. Programación Modular, Clases y Objetos.

// La versión correcta
@Override
public boolean equals(Object o) {
if( this == o ) return true; // Son el mismo objeto
if( o instanceof Punto2D ) {
Punto2D p = (Punto2D)o;
return x == p.x && y == p.y;
}
else
return false; // Son objetos distintos
}

E11. Corta el main de la clase Punto2D a una clase pública llamada


U04EA11 y haz que Punto2D no sea pública. Guarda los cambios en el
fichero U04EA11.java con el mismo nombre que la clase pública. Añade
estas dos nuevas líneas de código al main() de la clase de pública:
// Sentencia 1
if( p1.x >= 0 && p2.y >= 0) {
System.out.println( p1 + " en primer cuadrante" );
}
// Sentencia 2 equivalente
if( p1.getX() >= 0 && p2.getY() >= 0) {
System.out.println( p1 + " en primer cuadrante" );
}

Ahora, imagina que hemos descubierto que sería ventajoso usar


internamente un array para almacenar las coordenadas x e y de cada
Punto2D, la x en la posición 0, la y en la posición 1 del array. Así
podríamos fácilmente crear puntos 3D, 4D, 1D... Cambia el código de la
clase Punto2D y sustituye la línea: public double x, y; por double[] c;

8/11
UNIDAD 4. Programación Modular, Clases y Objetos.

Adapta el resto de código de la clase a esta nueva definición y


responde (de forma razonada y probando si es necesario) a estas
preguntas:
// Fichero U04EA11.java
public class U04EA11 {

public static void main(String[] args) {


Punto2D p1 = new Punto2D(3, 2.5);
Punto2D p2 = new Punto2D(1, -1);
Punto2D p3 = p1.suma( p2 );
System.out.println( p1 + " + " + p2 + " = " + p3);
p2.setX( p1.getX() );
p2.setY( p1.getY() );
System.out.println( p1 + " es igual a " + p2 + "? " +
p1.equals( p2) );
// Sentencia 1
if( p1.x >= 0 && p2.y >= 0) {
System.out.println( p1 + " en primer cuadrante" );
}
// Sentencia 2 equivalente
if( p1.getX() >= 0 && p2.getY() >= 0) {
System.out.println( p1 + " en primer cuadrante" );
}
}

class Punto2D {
public double[] c;

public Punto2D(double x, double y) {


c = new double[2];
c[0] = x;
c[1] = y;
}

public Punto2D() { this(0,0); }

public double getX() { return c[0]; }


public double getY() { return c[1]; }
public void setX(double x) { c[0] = x; }

9/11
UNIDAD 4. Programación Modular, Clases y Objetos.

public void setY(double y) { c[1] = y; }

public Punto2D suma(Punto2D p) {


Punto2D resul = new Punto2D();
if(p == null) {
resul.c[0] = c[0];
resul.c[1] = c[1];
return resul;
}
resul.c[0] = c[0] + p.c[0];
resul.c[1] = c[1] + p.c[1];
return resul;
}

public String toString(){ return "(" + c[0] + ", " + c[1] + ")"; }

@Override
public boolean equals(Object o) {
if( this == o ) return true; // Son el mismo objeto
if( o instanceof Punto2D ) {
Punto2D p = (Punto2D)o;
return c[0] == p.c[0] && c[1] == p.c[1];
}
else
return false; // Son objetos distintos
}
}

Hay fallos en el código que


accede directamente a las
variables miembro de Punto2D.
Es decir, cuando una clase
permite que código externo
acceda directamente a su
interior (no oculta su
implementación) aparecen
dependencias entre la
implementación del objeto (su
interior) y el código que usa al

10/11
UNIDAD 4. Programación Modular, Clases y Objetos.

objeto.

La segunda sentencia, al usar los getters y setters proporcionados por


la clase, está aislada de posibles cambios futuros en esa clase,
mientras no cambie la interfaz (los getters y setters).

• ¿A cuál de las dos líneas añadidas a main() afectará el cambio?


A la que accede directamente a las variables miembro, depende
de su existencia para ser correcto.
• ¿Es bueno usar los getters y setters de los objetos de una
clase en vez de acceder directamente a sus variables miembro?
Responde V (verdadero) y F (falso):
◦ Así la clase puede implementar reglas de negocio
(restricciones lógicas) y forzar su cumplimiento: V .
◦ Así los cambios internos en cada clase no afectan al código
que los usa si la interfaz no cambia: V .
◦ Asegurar los dos puntos anteriores exige que la clase oculte
(proteja al máximo) las variables miembro con los
modificadores de acceso adecuados): V .
◦ Lo razonable (salvo que existan causas que lo juestifiquen)
es declarar variables miembro como private y métodos de
uso externo como public: V .

11/11

También podría gustarte