Search code examples
javaexceptioncastingsubclasssuperclass

Exception java.lang.classCastException when cast subclass from SuperClass


Im getting the error in the title when I try to use the method getInfoDerivada() from Desguace:

Exception in thread "main" java.lang.ClassCastException: es.unex.cum.mdp.sesion2.Vehiculo cannot be cast to es.unex.cum.mdp.sesion2.Moto at es.unex.cum.mdp.sesion2.Desguace.getInfoDerivada(Desguace.java:93) at es.unex.cum.mdp.sesion2.Main.main(Main.java:21)

And I don't know how to cast the subclass Moto to use its method getPotencia() from superclass Vehiculo.

Thanks

package es.unex.cum.mdp.sesion2;

public class Main {

    public static void main(String[] args) {

        Persona p = new Persona();
        Vehiculo v = new Coche("Renault","Asd",p,1234,"azul");
        Vehiculo v1 = new Moto("a","b",p,2345,25);

        if(v.getClass().equals(Coche.class))
            System.out.println("holi 1.0");

        Desguace d = new Desguace("pepe",2);

        if(d.addVehiculo(v))
            System.out.println("ok");
        if(d.addVehiculo(v1))
            System.out.println("ok");

        String a = d.getInfoDerivada(1);
        String b = v1.toString();
        System.out.println(b);

        System.out.println(a);

    }

}

Class Desguace

package es.unex.cum.mdp.sesion2;

import java.util.Arrays;

public class Desguace {
    protected String nombre;
    protected Vehiculo [] vehiculos;
    protected Integer cont;


    public Desguace() {
        nombre = "";
        vehiculos = new Vehiculo[0];
        cont = 0;
    }

    public Desguace(String nombre, int cant) {
        this.nombre = nombre;
        vehiculos = new Vehiculo[cant];
        cont = 0;
    }

    public boolean addVehiculo (Vehiculo v){
        for(int i = 0; i < cont; i++)
            if(vehiculos[i].getBastidor() == v.getBastidor())
                return false;
        if(cont<vehiculos.length){
            vehiculos[cont] = new Vehiculo(v);
            cont = cont + 1;
            return true;
        }
        else
            return false;
    }

    public Vehiculo getVehiculoBastidor(Integer bastidor){
        if(bastidor < 0)
            return null;
        for(int i = 0; i < cont; i++){
            if(vehiculos[i].getBastidor()==bastidor)
                return vehiculos[i];
        }
        return null;
    }

    public boolean addPiezaVehiculo(Pieza p, Integer bastidor){
        if(bastidor < 0)
            return false;
        for(int i = 0; i < cont; i++){
            if(vehiculos[i].getBastidor() == bastidor){
                for(int j = 0; j < vehiculos[i].getCont(); j++){
                    if(vehiculos[i].getPiezaV(j).equals(p)){
                        vehiculos[i].getPiezaV(j).setContador(vehiculos[i].getPiezaV(j).getContador() + p.getContador());
                        return true;}
                    else{
                        if(vehiculos[i].getCont() < 3){
                            vehiculos[i].addPiezaV(p);
                            vehiculos[i].setCont(vehiculos[i].getCont()+1);
                        }
                        else
                            return false;
                    }
                }

            }
        }
        return false;
    }

    public Vehiculo mayorStock(){
        int aux = 0;
        if(vehiculos[aux] == null)
            return null;
        for(int i = 1; i < cont; i++){
            if(vehiculos[aux].getCont() < vehiculos[i].getCont())
                aux = i;
        }
        return vehiculos[aux];  
    }

    public String getInfoDerivada(int pos){
        if(pos < 0 || pos >= cont){
            return null;}
        if(vehiculos[pos].getClass() == Coche.class){
            return ((Coche)vehiculos[pos]).getColor();
        }
        if(vehiculos[pos].getClass() == Moto.class){
            return String.valueOf(((Moto)vehiculos[pos]).getPotencia());
        }
        if(vehiculos[pos].getClass() == Camion.class){
            return String.valueOf(((Camion)vehiculos[pos]).getTonelaje());
        }
            return String.valueOf(((Moto)vehiculos[pos]).getPotencia());
    }

    public String getNombre() {
        return nombre;
    }
    public void setNombre(String nombre) {
        this.nombre = nombre;
    }
    public Integer getCont() {
        return cont;
    }
    public void setCont(Integer cont) {
        this.cont = cont;
    }
    public Vehiculo[] getVehiculos() {
        return vehiculos;
    }

    @Override
    public String toString() {
        return "Desguace [nombre=" + nombre + "]";
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Desguace other = (Desguace) obj;
        if (cont == null) {
            if (other.cont != null)
                return false;
        } else if (!cont.equals(other.cont))
            return false;
        if (nombre == null) {
            if (other.nombre != null)
                return false;
        } else if (!nombre.equals(other.nombre))
            return false;
        if (!Arrays.equals(vehiculos, other.vehiculos))
            return false;
        return true;
    }



}

Class Vehiculo

package es.unex.cum.mdp.sesion2;

public class Vehiculo {
    protected String marca;
    protected String modelo;
    protected Persona propietario;
    protected Pieza[] piezas;
    protected Integer bastidor;
    protected Integer cont;

    public Vehiculo() {
        marca = "";
        modelo = "";
        propietario = new Persona();
        bastidor = 0;
        piezas=new Pieza[3];
        for(int i = 0; i < piezas.length; i++)
            piezas[i] = new Pieza();
        cont=0;
    }

    public Vehiculo(String marca, String modelo, Persona p, Integer bastidor) {
        this.marca = marca;
        this.modelo = modelo;
        this.bastidor = bastidor;
        propietario = new Persona(p.getNombre(),p.getDni(),p.getEdad());
        piezas=new Pieza[3];
        for(int i = 0; i < piezas.length; i++)
            piezas[i] = new Pieza();
        cont = 0;
    }

    public Vehiculo(Vehiculo p) {
        this(p.getMarca(),p.getModelo(),p.propietario, p.getBastidor());
    }

    public boolean addPiezaV(Pieza p) {
        for(int i = 0; i < cont; i++){
            if(piezas[i].equals(p))
                piezas[i].setContador(piezas[i].getContador()+p.getContador());
        }
        piezas[cont].setId(p.getId());
        piezas[cont].setNombre(p.getNombre());
        piezas[cont].setContador(p.getContador());
        cont = cont + 1;
        return true;

    }

    public Pieza getPiezaV(int pos) {
        if(pos >= piezas.length || pos < 0)
            return null;
        else
            return piezas[pos];


    }
    //getter y setter

    public String getMarca() {
        return marca;
    }

    public void setMarca(String marca) {
        this.marca = marca;
    }

    public String getModelo() {
        return modelo;
    }

    public void setModelo(String modelo) {
        this.modelo = modelo;
    }

    public Integer getBastidor() {
        return bastidor;
    }

    public void setBastidor(Integer bastidor) {
        this.bastidor = bastidor;
    }

    public Integer getCont(){
        return cont;
    }

    public void setCont(Integer cont){
        this.cont = cont;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Vehiculo other = (Vehiculo) obj;
        if (bastidor == null) {
            if (other.bastidor != null)
                return false;
        } else if (!bastidor.equals(other.bastidor))
            return false;
        if (cont == null) {
            if (other.cont != null)
                return false;
        } else if (!cont.equals(other.cont))
            return false;
        if (marca == null) {
            if (other.marca != null)
                return false;
        } else if (!marca.equals(other.marca))
            return false;
        if (modelo == null) {
            if (other.modelo != null)
                return false;
        } else if (!modelo.equals(other.modelo))
            return false;
        if (propietario == null) {
            if (other.propietario != null)
                return false;
        } else if (!propietario.equals(other.propietario))
            return false;
        return true;
    }

}

Class Moto

package es.unex.cum.mdp.sesion2;

public class Moto extends Vehiculo {
    protected Integer potencia;

    public Moto(){
        super();
        potencia = 0;
    }

    public Moto(String marca, String modelo, Persona p, Integer bastidor, Integer potencia){
        super(marca,modelo,p,bastidor);
        this.potencia = potencia;
    }

    public Integer getPotencia() {
        return potencia;
    }

    public void setPotencia(Integer potencia) {
        this.potencia = potencia;
    }

    @Override
    public String toString() {
        return "Moto[marca=" + marca + ", modelo=" + modelo + ", bastidor=" + bastidor + ", potencia=" + potencia +"]";
    }

}

Solution

  • You can convert a Moto to a Vehiculo without the need to check anything and the need to cast it as Moto is a sub class of Vehiculo but if you want to do the opposite you need to check first if your instance of Vehiculo is an instance of Moto using instanceof because an instance of Vehiculo is not necessary an instance of Moto which is root cause your problem here as you get a ClassCastException. Even worse here, according to your error message you try to cast an instance of Vehiculo to an instance of Moto which is simply not possible.

    if (vehiculos[pos] instanceof Moto) {
        // Here we can safety cast to a moto
        Moto moto = (Moto) vehiculos[pos];
        ...
    }
    

    Your problem is in the method getInfoDerivada when you reach the last case, you cast it to a Moto which cannot be the case as we already know that it is not an instance of Moto.

    Your code should be something like that:

    public String getInfoDerivada(int pos){
        if(pos < 0 || pos >= cont){
            return null;
        }
        if(vehiculos[pos] instanceof Coche){
            return ((Coche)vehiculos[pos]).getColor();
        } else if(vehiculos[pos] instanceof Moto){
            return String.valueOf(((Moto)vehiculos[pos]).getPotencia());
        } else if(vehiculos[pos] instanceof Camion){
            return String.valueOf(((Camion)vehiculos[pos]).getTonelaje());
        }
        throw new IllegalStateException(
            String.format("Unknown type: %s", vehiculos[pos].getClass().getName())
        );
    }
    

    Your bug is actually in addVehiculo, you are supposed to assign directly the instance of Vehiculo provided instead of creating a new instance of Vehiculo with it.

    public boolean addVehiculo (Vehiculo v){
        ...
        if(cont<vehiculos.length){
            vehiculos[cont] = v;// instead of new Vehiculo(v);
            ...
        }
        ...
    }
    

    A much better approach would be to add a new method getInfoDerivada in the class Vehiculo for which you will provide a default implementation then override it on the sub classes if needed, your code will simply be:

    public String getInfoDerivada(int pos){
        if(pos < 0 || pos >= cont){
            return null;
        }
        return vehiculos[pos].getInfoDerivada();
    }