Подтвердить что ты не робот

Гарантировать ковариантный тип возврата с помощью дженериков в Java

У меня есть класс под названием Point, с методом neighbors(), который возвращает массив Point s:

public class Point {
    public Point[] neighbors() { /* implementation not shown */ }
}

У меня есть подкласс Point, называемый SpecialPoint, который переопределяет neighbors(), чтобы вернуть массив SpecialPoint вместо Point s. Я думаю, что это называется ковариантными типами возврата.

public class SpecialPoint extends Point {
    public SpecialPoint[] neighbors() { /* implementation not shown */ }
}

В отдельном классе я хочу использовать Point и SpecialPoint с generics

public <P extends Point> P doStuff(P point) {
    P[] neighbors = point.neighbors();
    // more stuff here including return
}

Это не скомпилируется, потому что компилятор может гарантировать, что P является некоторым подклассом Point, но нет гарантии, что каждый подкласс Point переопределит neighbors(), чтобы вернуть массив из себя как Я, случается, сделал с SpecialPoint, поэтому Java знает, что P#neighbors() возвращает Point[], а не P[].

Как я гарантирую, что каждый подкласс переопределяет neighbors() с помощью ковариантного типа возврата, чтобы я мог использовать его с generics?

4b9b3361

Ответ 1

Вы можете использовать интерфейс:

public interface Point<P extends Point<P>> {
    P[] neighbors();
}

public class SimplePoint implements Point<SimplePoint> {
    @Override
    public SimplePoint[] neighbors() { /* ... */ }
}

public class SpecialPoint implements Point<SpecialPoint> {
    @Override
    public SpecialPoint[] neighbors() { /* ... */ }
}

Тогда:

public <P extends Point<P>> P doStuff(P point) {
    P[] neighbors = point.neighbors();
    /* ... */
}

Если вам все еще нужно разложить код между реализациями, тогда лучше использовать абстрактный класс:

public abstract class Point<P extends Point<P>> {
    public abstract P[] neighbors();
    public void commonMethod() { /* ... */ }
}

public class SimplePoint extends Point<SimplePoint> { /* ... */ }

public class SpecialPoint extends Point<SpecialPoint> { /* ... */ }

Ответ 2

Возможно, interface Point решает вашу проблему:

public class Test  
{

    public interface Point  {
        public Point[] neighbors();
    }

    public class SpecialPoint implements Point {
        public SpecialPoint[] neighbors() { return null; }
    }

    public class SpecialPoint2  implements Point {
        public SpecialPoint2[] neighbors() { return null; }
    }

    public Point doStuff(SpecialPoint point) {
        Point[] neighbors = point.neighbors();
        return neighbors[0];
    }

    public Point doStuff(SpecialPoint2 point) {
        Point[] neighbors = point.neighbors();
        return neighbors[0];
    }
}