Реализация интерфейса с суперклассами аргумента метода - PullRequest
6 голосов
/ 16 октября 2010

В качестве практического примера общего вопроса в предмете я хотел бы реализовать метод containsAll в интерфейсе Set с

public boolean containsAll(Iterable<?> c) { /* ... */ }

Я полагаю, что это должно быть разрешено, поскольку Collection равно Iterable, что означает, что containsAll будет соответствовать требованиям интерфейса. Аналогичным образом, в более общем смысле возможность реализации интерфейсов с аргументами суперклассов выглядит так, как будто они должны работать.

Однако, Eclipse не говорит ни слова (не пробовал просто javac) - может кто-нибудь объяснить причину этого? Я уверен, что в спецификации есть что-то, что делает его таким, каким он есть, но я бы хотел понять и мотивацию для требований. Или я пропускаю что-то вроде Iterable<?>, не являющееся суперклассом Collection<?>?

В качестве дополнительного вопроса - учитывая, что я объявляю два метода, будет ли метод с подписью Iterable всегда предпочтительнее для вызовов с аргументом Collection?

Ошибка затмения:

Если я удаляю метод с подписью Collection, просто оставляя Iterable (см. После ошибки), я получаю следующее:

The type BitPowerSet must implement the inherited abstract method Set<Long>.containsAll(Collection<?>)

Точная реализация:

@Override public boolean containsAll(Collection<?> c) {
  for (Object o : c) if (!contains(o)) return false;
  return true;
}
public boolean containsAll(Iterable<?> c) {
  for (Object o : c) if (!contains(o)) return false;
  return true;
}

Ответы [ 3 ]

5 голосов
/ 16 октября 2010

Поскольку интерфейс, который вы реализуете, объявляет (абстрактный) метод containsAll(Collection<?>), вы должны реализовать его с этой точной подписью.Java не позволяет вам реализовать / переопределить метод с более широким типом параметра, чем исходный.Вот почему вы получаете ошибку, которую вы показываете, когда вы закомментируете свой метод с подписью Collection.

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

2 голосов
/ 16 октября 2010

Я думаю, почему в Java есть такое ограничение, скажем, у вас есть:

class A {
    void foo(String s) { ...  }
}

class B extends A {
    // Note generalized type
    @Override void foo(Object s) { ...  }
}

Теперь, если у вас есть class C extends B и он хочет переопределить foo, неясно, какой аргумент он должен принять.

Скажем, например, C расширил сначала A напрямую, переопределив void foo(String s), а затем он был изменен на расширение B. В этом случае существующее переопределение C foo станет недействительным, потому что foo B должен обрабатывать все Object с, а не просто String с.

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

Типы аргументов являются частью сигнатуры метода, поэтому jvm нужен метод с точно такой же сигнатурой для поиска переопределений.В объекте containsAll (Iterable) будет использоваться подпись, отличная от сигнатуры containsAll (Collection).

Если я правильно помню, компилятор должен использовать некоторые обходные пути, чтобы универсальные шаблоны работали, несмотря на это ограничение.Ваш второй вопрос, компилятор предпочел бы аргумент Collection, поскольку он является подтипом Iterable, что делает метод Collection более специфичным, чем Iterable.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...