I have an abstract class:
public abstract class AbstractPoint<PointType extends AbstractPoint<PointType>> {
public abstract double getX();
public abstract double getY();
public abstract double rho();
// Find the distance between two points
public final <T extends AbstractPoint<T>> double distance(T other) {
return vectorTo(other).rho();
}
// Find vector from one point to another.
public abstract <T extends AbstractPoint<T>> PointType vectorTo(T other);
// other methods ...
}
Classes OrthogonalPoint
and PolarPoint
extend the abstract class:
public class OrthogonalPoint extends AbstractPoint<OrthogonalPoint> {
private double x;
private double y;
public OrthogonalPoint(double x, double y) {
this.x = x;
this.y = y;
}
public double getX() { return this.x; }
public double getY() { return this.y; }
public double rho() { return Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2)); }
public double theta() { return Math.atan2(this.y, this.x); }
public <T extends AbstractPoint<T>> OrthogonalPoint vectorTo(T other) {
return new OrthogonalPoint(other.getX() - this.x, other.getY() - this.y);
}
}
public class PolarPoint extends AbstractPoint<PolarPoint> {
private double rho;
private double theta;
public PolarPoint(double x, double y) {
this.rho = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2));
this.theta = Math.atan2(y, x);
}
public double getX() { return this.rho() * Math.cos(this.theta()); }
public double getY() { return this.rho() * Math.sin(this.theta()); }
public double rho() { return this.rho; }
public double theta() { return this.theta; }
public <T extends AbstractPoint<T>> PolarPoint vectorTo(T other) {
return new PolarPoint(other.getX() - this.getX(), other.getY() - this.getY());
}
}
With this code, I can correctly calculate the distance between points no matter whether they are of same type (orthogonal or polar).
Now I add another class called Route
:
public class Route {
private final List<? extends AbstractPoint<?>> points = new ArrayList<>();
// 'point' in 'this.points.add(point)' underlined red
public <T extends AbstractPoint<T>> void appendPoint(T point) { this.points.add(point); }
public <T extends AbstractPoint<T>> void removePoint(T point) { this.points.remove(point); }
// 'point' in '.distance(point)' underlined red
public double routeDistance() {
return this.points.stream().skip(1).mapToDouble(point ->
this.points.get(this.points.indexOf(point) - 1).distance(point)).sum();
}
}
A route is an ordered number of points whose length is defined as the sum of the distances of the points in the sequence. So, if a route consists of three points (p1, p2, and p3) the distance of the route is p1.distance(p2) + p2.distance(p3)
.
However, some places (look at the comments in Route
) in my code are underlined red:
// in appendPoint function
Required type: capture of ? extends AbstractPoint<?>
Provided: T
// in routeDistance function
Required type: T
Provided: capture of ? extends AbstractPoint<?>
I want to be able to add any type of point to the points list and the call routeDistance
function to calculate the length of the route. What is wrong with my solution - how should I change my generics (in any class)?