Your CityConverter extends AbstractConverter
and AbstractConverter<T>
requires implementation for
public abstract T convert(AbstractEntity e);
It is not a problem that extends AbstractConverter
uses raw-types because overridden method can be more specific in case of returned object (since it is still of type described by parent class).
But problem appears when in derived class you want to require more specific type as argument.
Remember that derived class can still be used from reference which is of one of parents type like it is possible to have code like:
AbstractConverter ac = new CityConverter();
So when we will invoke ac.convert(...)
compiler will allow us to use any type of AbstractEntity
as argument, not only CityEntity
which could brake code of CityConverter#convert
.
Which is why we can't declare more specific type of method argument when overriding it.
Now about question from your title:
Why do I need cast in this case?
...
CityEntity cityEntity = (CityEntity) entity;
you need casting because entity
is declared to be AbstractEntity
which means there is a chance that passed instance may not be of type CityEntity
so compiler can't compile code like:
CityEntity cityEntity = entity;//error without cast
By casting you are basically saying "I am sure that passed instance will be of type (CityEntity)
and if not, I am willing to face consequences and am ready to see my application stopped by ClassCastException".