Autor Tema: Java diferencia entre protected private y public clases y métodos abstractos abs  (Leído 2926 veces)

rob25

  • Sin experiencia
  • *
  • APR2.COM
  • Mensajes: 10
    • Ver Perfil
Buenas tengo una duda con las clases abstractas en Java.

Tengo la superclase Transporte la cual tiene los atributos privados y metodos y getters y setters abstractos y luego la clase Barco que hereda de Transporte tiene su constructor con otros atributos y luego los metodos que son herededados de clase abstracta Transporte.

Mi duda es como puedo hacer que la Clase Barco los getters y Setters retornen los valores como GetPrecio() retorne precio en vez de 0.

Adjunto los codigos:

CLASE TRANSPORTE:

Código: [Seleccionar]
public abstract class Transporte {

private float precio;
private Date tiempo;
private int capacidad;

public abstract void VelocidadMedia();

public abstract void Salida();

public abstract float getPrecio();;

public abstract int getCapacidad();

public abstract void setCapacidad(int capacidad);

public abstract void setPrecio(float precio);

public abstract Date getTiempo();

public abstract void setTiempo(Date tiempo);

}


CLASE BARCO:

Código: [Seleccionar]
public class Barco extends Transporte{

private int categoria;



public Barco(int categoria) {
super();
this.categoria = categoria;

if(categoria==1) {
setPrecio(120);
}

if(categoria==2) {
setPrecio(97);
}

if(categoria==3) {
setPrecio(89);
}

if(getCapacidad()>=1000) {
setPrecio((float) (getPrecio()*0.09));
setPrecio(getPrecio()-getPrecio());

}
}



public int getCategoria() {
return categoria;
}







@Override
public void VelocidadMedia() {



}

@Override
public void Salida() {

System.out.println("BARCO: Precio: " + getPrecio() + "Tiempo: " + "" + "Capacidad: " + getCapacidad() + "Categoria: " + getCategoria());

}



@Override
public float getPrecio() {

return 0;
}



@Override
public int getCapacidad() {

return 0;
}



@Override
public void setCapacidad(int capacidad) {


}



@Override
public void setPrecio(float precio) {


}



@Override
public Date getTiempo() {
return null;
}



@Override
public void setTiempo(Date tiempo) {

}



}
« Última modificación: 13 de Septiembre 2020, 19:25 por Ogramar »

Kabuto

  • Moderador Global
  • Experto
  • *******
  • Mensajes: 988
    • Ver Perfil
Re:Duda Java clases abstractas
« Respuesta #1 en: 03 de Abril 2020, 00:15 »
Hola.
Tienes dos opciones.

Una es declarar los atributos de Transporte como protected
Esto es que estaríann a medio camino entre private y public.

En protected sigues impidiendo que cualquier clase pueda acceder a estos atributos directamente.
Sin embargo, permites que las clases hijas que hereden de Transporte, sí puedan acceder libremente a estos atributos.

Así, si pones precio como protected:

Código: [Seleccionar]
public abstract class Transporte {

protected float precio;
private Date tiempo;
private int capacidad;

Luego sus clases hijas como Barco, tienen acceso al atributo, usando la palabra reservada super para llamar a su clase padre:

Código: [Seleccionar]
@Override
public float getPrecio() {
return super.precio;
}

Esta es una opción.

La otra, consiste en conservar el atributo precio como private, pero lo que haremos será que la clase Transporte, su método getPrecio() NO será abstracto. Será como un getter normal y corriente.

Código: [Seleccionar]
public abstract class Transporte {

private float precio;
private Date tiempo;
private int capacidad;

public abstract void VelocidadMedia();

public abstract void Salida();

public float getPrecio() {
return precio;
}

De este modo, la clase Barco ya hereda directamente un método para devolver el precio.
No necesita que le hagas un getter para el precio, porque ya va a tener el que hereda de su superclase Transporte.

Sin embargo, puede que sí quieras que Barco tenga su propio getter para el precio según el ejercicio que esté realizando.

No parece ser el caso, pero vamos a suponer que tu quieres que las clases hijas de Transporte complementen el precio cada una a su manera.
Vamos a suponer que el atributo precio de Transporte es el precio básico. Pero que por ejemplo si es un Barco, a ese precio hay que añadirle un 15% por un impuesto exclusivo que tienen todos los Barcos.

En este caso, puede sobreescribir el método getPrecio que se hereda de Transporte y complementar el precio básico con dicho impuesto.
De nuevo, usamos la palabra super, pero para acceder al método heredado, no al atributo ya que no es visible al ser private.
Así la clase Barco tendría este método:
Código: [Seleccionar]
@Override
public float getPrecio() {
//Los barcos tienen un impuesto del 15%
return super.getPrecio() * 1.15f;
}
Si otra clase hija, tuviera un impuesto distinto, por ejemplo Helicoptero un impuesto del 30% si su potencia es de 150hp y 35% si es de 250hp, pues también sobreescribiría el método que hereda de la superclase para adecuarlo a sus necesidades.

Resumiendo, tienes en realidad tres opciones:
1- Superclase con atributos protected y métodos abstractos.
Las clases hijas estarán OBLIGADAS a sobreescribir los métodos abstractos que heredan, pero tendrán visibilidad para acceder libremente a los atributos de la superclase y operar con ellos.

2- Superclase con atributos private y métodos no abstractos que ya se encargan de operar con los atributos
Las clases hijas NO tienen visibilidad para acceder a los atributos de la superclase, pero en realidad no lo necesitan porque ya HEREDAN los métodos de la superclase que operan con sus atributos.

3- Superclase con atributos private y métodos no abstractos, que serán sobreescritos por las clases hija
Las clases hijas NO tienen acceso a los atributos de la superclase. HEREDAN los métodos de la superclase que ya operan con esos atributos, pero como la clase hija necesita COMPLEMENTAR con sus peculiaridades propias la operación a realizar con dichos atributos, van a SOBREESCRIBIR  los métodos heredados.



¿Cuál es la mejor de estas opciones?
Ninguna, depende de cada caso y de según prefiera cada programador.

No hay nada de malo en usar la instrucción protected, seguro que profesores te habrán insistido que los atributos han de ser siempre private y esto es cierto el 95% de las veces.
Sin embargo, habrá veces que te ahorres código o te facilite las cosas ampliar la visibilidad de un atributo con protected, o incluso con public, siempre que uno sepa bien lo que está haciendo.

Dicho esto, yo por lo general los mantengo como private y hago que la superclase ya tenga métodos operativos para estos atributos listos para ser heredados por sus hijas.
Y si estas necesitan sobreescribirlos para algo, pues que los sobreescriban.

Espero haberme explicado bien. Repregunta lo que sea.

Un saludo.
« Última modificación: 03 de Abril 2020, 00:19 por Kabuto »
NO respondo dudas por mensaje privado
Publicando vuestras dudas en el foro público conseguimos:
- Que más gente aporte respuestas mejores o complementarias.
- Que otras personas puedan aprender de vuestras dudas.

Mejor en PÚBLICO que en privado. Gracias

rob25

  • Sin experiencia
  • *
  • APR2.COM
  • Mensajes: 10
    • Ver Perfil
Re:Duda Java clases abstractas
« Respuesta #2 en: 03 de Abril 2020, 14:58 »
Muchas gracias, ya me ha quedado mas claro. He usado la segunda opción y funciona perfectamente.

Ahora tengo otra duda.

Tengo un atributo en la clase Transporte llamado Tiempo de tipo Date(Uso java.Util.Date). Con este atributo necesito sacar los tiempos para cada subClase, por ejemplo Barco: 7 horas, Avion: 30 minutos.

Mi duda es que no se usar los atributos tipo Date para sacar las horas y minutos. Creo que tengo que crear otro atributo llamado horas y otro llamados minutos. Luego creo que tengo que crear un nuevo Date e instanciarlo con Calendar e igualar los atributos horas y minutos a Calendar.Hour i Calendar.Minutes.

Muchas gracias.

Código: [Seleccionar]
import java.util.Date;

public abstract class Transporte {

private float precio;
[b]private Date tiempo;[/b]
private int capacidad;


Kabuto

  • Moderador Global
  • Experto
  • *******
  • Mensajes: 988
    • Ver Perfil
Re:Duda Java clases abstractas
« Respuesta #3 en: 04 de Abril 2020, 00:35 »
No estoy muy seguro de que quieres representar exactamente con el atributo tiempo.

Si quieres representar simplemente el número de horas que tarda en realizar su recorrido:
7 horas, 2 horas, etc...
Puedes usar simplemente un atributo int que trabaje con minutos y dividiendo por 60 puedes convertir a horas.
Haciendo mod de 60 obtienes el resto para mayor precisión.

Por ejemplo,
tiempo = 450;(minutos)

tiempo / 60 --> 450 / 60 = 7 (horas enteras)
tiempo mod 60 --> 450 % 60 = 30 (resto minutos)

450 minutos son 7 horas y 30 minutos.



Es distinto si quieres representar un tiempo concreto del día
Supongamos que queremos representar la hora a la que sale cada objeto Transporte
Uno sale a las 10:00 de la mañana, otro sale a las 15:30, otro sale  a las 20:45....

Y queremos preguntarle al programa que Transporte ha salido ya o cuál no ha salido todavía.

La clase Calendar está algo oxidada ya...
Y Date se considera obsoleta.

Es mejor usar otras clases más nuevas como LocalDate o LocalTime.
Puesto que en este ejemplo solo nos interesa el tiempo y no fechas, es mejor usar LocalTime.

Así la clase Transporte puede usar un atributo de este tipo.
Y el get y set para tiempo, dejan de ser abstractos y es la superclase Transporte quien tiene el código para gestionar.
Fíjate que para setear el tiempo, usamos dos int, uno representa la hora y la otra el minuto

Código: [Seleccionar]
import java.time.LocalTime;

public abstract class Transporte {

private float precio;
private LocalTime tiempo;
private int capacidad;

public abstract void VelocidadMedia();

public abstract void Salida();

public float getPrecio() {
return precio;
}

public int getCapacidad() {
return capacidad;
}

public abstract void setCapacidad(int capacidad);

public abstract void setPrecio(float precio);

public LocalTime getTiempo() {
return tiempo;
}

public void setTiempo(int hora, int minuto) {
tiempo = LocalTime.of(hora, minuto);
}
}

Podemos hacer ahora un código para probar como funciona ese atributo.
Este es un programita que hace una lista de tres Barcos en un array.

Hay un método que, según la hora actual (coge la hora del sistema), nos dice que barcos han zarpado ya, y si no lo han hecho, nos dice a que hora salen y cuanto tiempo falta para que zarpen:
Código: [Seleccionar]
import java.time.LocalTime;
import java.time.temporal.ChronoUnit;

public class Prueba {

private static Barco[] barcos; //Listado de barcos

public static void main(String[] args) {

//Creamos lista e indicamos sus horas de salida
barcos = new Barco[3];

barcos[0] = new Barco(1);
barcos[0].setTiempo(10, 0);//Sale a las 10:00
barcos[1] = new Barco(2);
barcos[1].setTiempo(15, 30);//Sale a las 15:30
barcos[2] = new Barco(3);
barcos[2].setTiempo(22, 45);//Sale a las 22:45

comprobarHorarios();
}

/**
* Recorre la lista de Barcos e indica que barcos han salido ya
* y los que no han salido, cuanto tiempo falta para que salgan
*/
public static void comprobarHorarios() {
//Recogemos la hora actual, a partir de la hora del sistema
LocalTime ahora = LocalTime.now();
System.out.println("Hora actual: " + ahora.getHour() + ":" + ahora.getMinute());

for (int i = 0; i < barcos.length; i++) {

if (barcos[i].getTiempo().isAfter(ahora)) { //Este barco aún no ha salido

System.out.println("\n\nHay un Barco disponible a las " + barcos[i].getTiempo().toString());
long minutosHastaSalir = ahora.until(barcos[i].getTiempo(), ChronoUnit.MINUTES);
int horas = (int) (minutosHastaSalir / 60);
int minutos = (int) (minutosHastaSalir % 60);
System.out.println("Faltan " + horas + " horas y " + minutos + " minutos para zarpar");
}
else { //Este barco ya ha salido
System.out.println("\n\nHay un barco que ya ha zarpado a las " + barcos[i].getTiempo().toString());
System.out.println("No estará disponible hasta mañana");
}
}
}

}

En pantalla nos sale un resultado como este:
Citar
Hora actual: 0:20


Hay un Barco disponible a las 10:00
Faltan 9 horas y 39 minutos para zarpar


Hay un Barco disponible a las 15:30
Faltan 15 horas y 9 minutos para zarpar


Hay un Barco disponible a las 22:45
Faltan 22 horas y 24 minutos para zarpar

Si engaño en el código para decir que "ahora" son las 15:25
Código: [Seleccionar]
//Recogemos la hora actual, a partir de la hora del sistema
LocalTime ahora = LocalTime.of(15, 25);

En pantalla tenemos
Citar
Hora actual: 15:25


Hay un barco que ya ha zarpado a las 10:00
No estará disponible hasta mañana


Hay un Barco disponible a las 15:30
Faltan 0 horas y 5 minutos para zarpar


Hay un Barco disponible a las 22:45
Faltan 7 horas y 20 minutos para zarpar


Esta podría ser una forma de hacerlo. Todo depende de qué quieres representar exactamente con el atributo tiempo que, repito, aún no me ha quedado claro.

Incluso se puede combinar. Un atributo para la hora de salida y otro atributo para indicar la duración del viaje.
De ese modo, solo con indicar la hora de salida, se puede hacer el cálculo de cuál sera la hora de llegada, puesto que hay otro atributo para indicar la duración.


En cualquier caso, ahora ya conoces la clase LocalTime, que es una maravilla. Oracle la introdujo junto con LocalDate cuando lanzó Java8, porque Calendar, Date y otras necesitaban modernizarse.

Un saludo.
« Última modificación: 04 de Abril 2020, 00:42 por Kabuto »
NO respondo dudas por mensaje privado
Publicando vuestras dudas en el foro público conseguimos:
- Que más gente aporte respuestas mejores o complementarias.
- Que otras personas puedan aprender de vuestras dudas.

Mejor en PÚBLICO que en privado. Gracias

rob25

  • Sin experiencia
  • *
  • APR2.COM
  • Mensajes: 10
    • Ver Perfil
Re:Duda Java clases abstractas
« Respuesta #4 en: 04 de Abril 2020, 17:59 »
Buenas antes de nada muchas gracias por la ayuda que me estas dando, me está siendo de gran ayuda aprender tanto contigo.

No me explique muy bien lo que queria hacer con el atributo Tiempo.

Dentro de la clase Transporte tengo un atributo tiempo de tipo date, según el enunciado. Lo que me pide el ejercicio es lo siguiente:

Me pide que calcule las velocidades medias, para ello esta el metodo VelocidadMedia() que es heredado a la clase Barco. Para calcular el la velocidad media hay que dividir el tiempo entre la distancia, que se pediran ambos por parametro y el metodo VelocidadMedia() debera resolverla.

El tiempo de barco son 7 horas, Avion 30 minutos..

La distancia fija sera siempre de 800km

Por ejemplo habria que dividir las 7 horas del barco entre los 800km para sacar la velocidad media de subclase barco.

Mi duda sigue siendo el atributo tipo date por que yo no puedo dividir un atributo de tipo date entre un atributo int como 800km. Se me exige que use Date como tipo de atributo aunque con LocalTime seria mas sencillo.

Tambien mi duda es que se me pide que pida por parametro las distancia aunque se dice que siempre sera de 800km y en el UML no hay ningun atributo distancia. ¿Lo deberia crear?
 
Gracias de nuevo Kabuto.
« Última modificación: 13 de Septiembre 2020, 19:28 por Ogramar »

Kabuto

  • Moderador Global
  • Experto
  • *******
  • Mensajes: 988
    • Ver Perfil
Re:Duda Java clases abstractas
« Respuesta #5 en: 05 de Abril 2020, 00:17 »
Mira, una de las principales dificultades para aprender programación, por no decir la mayor de todas, es encontrarle el sentido a los enunciados de los ejercicios que a menudo resultan incongruentes.

La clase Date está pensada para modelar fechas (Date = Fecha)
Date sirve para representar un instante concreto del tiempo, por ejemplo, el 4 de Abril de 2020, a las 23:00 de la noche.

No sirve para representar magnitudes de tiempo: 2 horas, 120 minutos, 7200 segundos...
con las que luego hacer operaciones aritméticas.

Yo ignoraría la premisa de usar la clase Date y haría lo que dije al principio de mi anterior mensaje, usar un simple int que trabaje con minutos.

Sobre los parámetro de tiempo y distancia, como tú mismo te has dado cuenta, de nuevo es incongruente el enunciado.

Si nos dicen que la distancia SIEMPRE va a ser de 800 km para TODOS los Transportes, a mi lo que me parecería lógico es crear un atributo con valor constante en la clase Transporte.
Y este es además uno de esos ejemplos donde se puede poner protected o incluso public, ya que al ser constante por muy visible que sea, no hay riesgo de que sea alterado.

Código: [Seleccionar]
public abstract class Transporte {

private float precio;
private Date tiempo;
private int capacidad;
protected final int DISTANCIA = 800; //Kilómetros

Pero bueno, si te dicen que luego se ha de pedir por parámetro, pues nada, no crearemos ese atributo y el valor de 800 lo pasaremos por parámetro.
Pero lo que si que hay que hacer, es declarar en el método abstracto que se ha de recibir una distancia por parámetro.
E insisto que tiempo ha de ser int, y sus get y set dejan de ser abstractos

Código: [Seleccionar]
public abstract class Transporte {

private float precio;
private int tiempo;
private int capacidad;

public abstract void VelocidadMedia(int distancia);

public int getTiempo() {
return tiempo;
}

public void setTiempo(int tiempo) {
this.tiempo = tiempo;
}

La clase Barco, en su constructor seteamos el tiempo de 7 horas llamando al método de la superclase.

Código: [Seleccionar]
public class Barco extends Transporte{

private int categoria;

public Barco(int categoria) {
super.setTiempo(420); //en minutos = 7 horas
this.categoria = categoria;

if(categoria==1) {
setPrecio(120);
}

Con esto ya establecido, ya solo hay que añadir código al método calcularDistancia() de la clase Barco.
Ahora que hemos decidido operar con valores int para la distancia y para el tiempo, no hay problemas para hacer cálculos.

Parece que se pide la velocidad media en nudos, creo que sería como pongo a continuación, pero si quieres intentar hacer el cálculo tú primero, pues no lo leas todavía  ;)

Un saludo.

Código: [Seleccionar]
@Override
public void VelocidadMedia(int distancia) {
int kmHora = distancia / (super.getTiempo() / 60); //Tiempo hay que convertir a horas
float nudos = kmHora * 0.54f;
System.out.println(String.format("Velocidad media en nudos: %.2f", nudos));
}
NO respondo dudas por mensaje privado
Publicando vuestras dudas en el foro público conseguimos:
- Que más gente aporte respuestas mejores o complementarias.
- Que otras personas puedan aprender de vuestras dudas.

Mejor en PÚBLICO que en privado. Gracias

rob25

  • Sin experiencia
  • *
  • APR2.COM
  • Mensajes: 10
    • Ver Perfil
Re:Duda Java clases abstractas
« Respuesta #6 en: 06 de Abril 2020, 22:53 »
Muchas gracias por la ayuda Kabuto.

He conseguido ya acabar todo el codigo y me funciona todo perfectamente.

Gracias por dedicar tu tiempo en ayudarme.

Un saludo.

Kabuto

  • Moderador Global
  • Experto
  • *******
  • Mensajes: 988
    • Ver Perfil
Re:Duda Java clases abstractas
« Respuesta #7 en: 07 de Abril 2020, 17:14 »
No hay de qué. ;D

Un saludo.
NO respondo dudas por mensaje privado
Publicando vuestras dudas en el foro público conseguimos:
- Que más gente aporte respuestas mejores o complementarias.
- Que otras personas puedan aprender de vuestras dudas.

Mejor en PÚBLICO que en privado. Gracias

 

Sobre la educación, sólo puedo decir que es el tema más importante en el que nosotros, como pueblo, debemos involucrarnos.

Abraham Lincoln (1808-1865) Presidente estadounidense.

aprenderaprogramar.com: Desde 2006 comprometidos con la didáctica y divulgación de la programación

Preguntas y respuestas

¿Cómo establecer o cambiar la imagen asociada (avatar) de usuario?
  1. Inicia sesión con tu nombre de usuario y contraseña.
  2. Pulsa en perfil --> perfil del foro
  3. Elige la imagen personalizada que quieras usar. Puedes escogerla de una galería de imágenes o subirla desde tu ordenador.
  4. En la parte final de la página pulsa el botón "cambiar perfil".