Невозможно скомпилировать класс, который реализует интерфейс без параметра типа - PullRequest
6 голосов
/ 01 октября 2010

У меня есть следующий тестовый код:

public interface Container<I> {
    public void addClass(Class<?> clazz);
}

public class MyContainer implements Container {
    public void addClass(Class<?> clazz) {}
}

и я получаю следующую ошибку при попытке скомпилировать эти два класса:

MyContainer.java: 1: MyContainer не является абстрактным и не перекрывает абстрактный метод addClass (java.lang.Class) в контейнере

Если я добавлю тип в интерфейс контейнера в MyContainer (например, <Object>), я не получу сообщение об ошибке.

Проблема в том, что я ввожу параметр типа в Container, который является частью общедоступного API, поэтому для совместимости я не могу иметь все реализующие классы, которые не могут компилироваться.

У кого-нибудь есть идеи? Это проблема стирания типа? Есть ли обходной путь?

Ответы [ 4 ]

7 голосов
/ 01 октября 2010

Я думаю, что проблема в том, что если вы используете необработанные типы в любом месте объявления класса, вы как бы отказываетесь от обобщений. Так что это сработает - обратите внимание на изменение параметра.

public class MyContainer implements Container {
    public void addClass(Class clazz) {}
}

С раздел 4.8 JLS :

суперклассы (соответственно, суперинтерфейсы) необработанного типа являются стирание суперклассов (суперинтерфейсы) любого из его параметризованные вызовы.

Я считаю это соответствующий бит ... стирание Container<T>.addClass(Class<?> clazz) равно addClass(Class clazz).

Но да, в основном, если это не настоящий устаревший код, вы должны рассматривать введение параметра типа в интерфейс как серьезное изменение.

3 голосов
/ 01 октября 2010

Если ваш класс использует Generics, то простое решение было бы сделать это:

interface Container<I> {
    public void addClass(Class<?> clazz);
}

class MyContainer<I> implements Container<I> {
    public void addClass(Class<?> clazz) {}
}

Или, если вы уже знаете тип вашего контейнера,

class MyContainer implements Container<ContainerType> {
    public void addClass(Class<?> clazz) {}
}

класс не использует Generics (до 1.5), тогда у вас не может быть части <?>.Так что здесь не будет никаких реальных проблем.

class MyContainer implements Container {
    public void addClass(Class clazz) {}
}
3 голосов
/ 01 октября 2010

Избавляемся, если <?> исправляет это:

public void addClass(Class clazz) {}

Сообщение об ошибке не очень наглядно:

Конфликт имен: метод addClass (Class) типаMyContainer имеет такое же стирание, что и addClass (Class) типа Container, но не переопределяет его

Это будет означать, что оба ваших метода одинаковы при удалении их типов, но метод подкласса фактически нереализовать / переопределить один из суперкласса / интерфейса.Это не имеет особого смысла, и я предполагаю, что это потому, что вы решили не использовать дженерики в своем подклассе, вы должны придерживаться этого (а не perameterize Class)

0 голосов
/ 01 октября 2010

Реализация вашего интерфейса должна работать следующим образом (согласно типу стирания):

public class MyContainer implements Container {
    public void addClass(Class clazz) {}
}
...