Reputation: 4969
Sorry for the title, couldn't come up with anything clearer. I have the following structure:
public interface Vehicle {...}
public class Car implements Vehicle {...}
then:
public abstract class Fixer {
...
abstract void fix(Vehicle vehicle);
...
}
and would like to have:
public class CarFixer extends Fixer {
void fix(Car car) {...}
}
but this doesn't work. Eclipse says: The type CarFixer must implement the inherited abstract method Fixer.fix(Vehicle)
. Any idea how can I solve this?
Upvotes: 3
Views: 1691
Reputation: 15113
You've met the humble home of generics.
Generics provide kind of 'wildcard' type where a class or method can specify that 'we don't really care what type it is, we just need -a- type'.
Generics allow a super class to enforce a specific type in a child class instead of allowing any class that extends a certain class.
This means that you're ultimately enforcing a new highest allowed super-class as the parameter (i.e. Vehicle
is no longer the most basic allowable type you can pass to fix()
; it's now whatever the subclass says it is, so long as that arbitrary type extends Vehicle
).
Common places for generics are container classes (i.e. List
, Map
, and Set
) where the container doesn't really care about what type it tracks, but rather focuses on actually tracking and managing those instances.
Generics consist of one or more type placeholders (in Java, E
and T
are commonly used but the name doesn't really matter; they usually follow the normal type naming conventions) that are used in place of a specific class or super class.
In your code, you want subclasses to implement methods given their exact relevant types (i.e. a CarFixer
would take Car
s, a JetpackFixer
would take Jetpack
s) but you want to enforce that these types extend Vehicle
.
In order to enforce this, you have to tell the Fixer
class exactly what your subclass wants.
public abstract class Fixer <E extends Vehicle>
{
abstract void fix(E vehicle);
}
Your subclass then extends Fixer, filling in E
with the type it wants.
public class CarFixer extends Fixer<Car>
{
@Override
void fix(Car vehicle)
{
// ...
}
}
Upvotes: 3
Reputation: 7994
You can use Generics to solve this:
public abstract class Fixer<T extends Vehicle> {
abstract void fix(T vehicle);
}
public class CarFixer extends Fixer<Car> {
void fix(Car car) {...}
}
The problem with your original version is that the fix
method allows any type of vehicle, but your implementing class allows only cars. Consider this code:
Fixer fixer = new CarFixer();
fixer.fix(new Bike()); // <-- boom, `ClassCastException`, Bike is a vehicle but not a car
Upvotes: 9