Не удалось открыть реализацию для метода, добавленного в интерфейс из базового класса в Eclipse

#java #eclipse #interface #abstract-class

#java #eclipse #интерфейс #абстрактный класс

Вопрос:

Я использую Eclipse Neon.

По сути, я создаю новый интерфейс и добавляю к нему существующий метод, найденный в другом базовом классе.

У меня есть класс, MyServiceImpl который расширяет базовый класс GeneralServiceImpl абстрактным методом doB .

Я создал интерфейс GeneralService для GeneralServiceImpl и добавил также doB метод:

 public interface GeneralService {    
    abstract void doB();
}

public class GeneralServiceImpl implements GeneralService {
   @Override
   public void doB() { }
   }
}
@Service
public class MyServiceImpl extends GeneralServiceImpl implements MyService {
     @Override
     public void doC() { }
}
  

И мой новый интерфейс включает ожидание использования GeneralServiceImpl метода doB()

 public interface MyService {
    public void doC();
    public void doB();
}
  

Это работает, но в eclipse, когда я нажимаю на doB() метод ( doC() работает) в MyService Open Implementation (Ctrl щелчок левой кнопкой мыши), я не могу найти какую-либо доступную реализацию (см. Ниже)

Это ошибка Eclipse? Неправильно ли сконструирован мой параметр? мои ожидания неверны?

  • Примечание от GeneralService я могу открыть реализацию для своего doB() метода

  • Обратите внимание, что еще одна причина, по которой мне это нужно, также заключается в добавлении поддержки Spring Service к существующему методу

Комментарии:

1. На какое слово, в какой строке опубликованного вами кода вы нажимаете мышью?

2. @Abra doD() в MyService . Обновил мой вопрос

3. У меня работает с Eclipse Oxygen в Windows 7 с Java 8.

4. @Abra Я использую Eclipse Neon

Ответ №1:

Пожалуйста, смотрите, это не ошибка.

Давайте разберемся (я сделал графическое представление, чтобы лучше понять):

введите описание изображения здесь

Ясно, что GeneralServiceImpl класс переопределяет doB() функцию реализации интерфейса GeneralService , а также MyServiceImpl реализует doC() функцию своего реализующего интерфейса MyService .

Кроме того, существует отношение наследования между MyServiceImpl и GeneralServiceImpl —> MyServiceImpl extends GeneralServiceImpl , поэтому MyServiceImpl имеет doB(){} значение.

Теперь мы должны понять, что IDE, завершение и компилятор используют статическое представление.

Если вы хотите узнать представление времени выполнения, то нужно использовать режим отладки.

Итак, если мы видим, как спроектированы ваши классы и интерфейс, между MyService и GeneralServiceImpl нет прямой связи, поэтому eclipse не известно о его runtime реализации и, следовательно, не выделяет то же самое.

Скорее, эта пунктирная линия на диаграмме представляет runtime отношение и, следовательно, реализацию функции void doB(); .


Добавление дополнительной информации на основе комментария @howlger :

Для Interface реализации class следует переопределить все объявленные функции (за исключением abstract случаев). и как IDE Eclipse при поиске реализации функции из Interface , тогда он ищет только прямую реализацию в реализующих классах. (вроде для doC() этого работает). [статический вид / компилятор]

Теперь представьте, что между MyServiceImpl amp; GeneralServiceImpl у нас есть другой класс, SubGeneralServiceImpl который также overrides doB() как

 public class SubGeneralServiceImpl extends GeneralServiceImpl {
    public void doB() {
            //
        }
    }
  

и теперь MyServiceImpl расширяется SubGeneralServiceImpl и SubGeneralServiceImpl еще больше расширяется GeneralServiceImpl .

Итак, даже сейчас MyServiceImpl есть doB(), но теперь доступен доступ к двум реализациям doB (), которые можно увидеть :

введите описание изображения здесь

таким образом, в статическом представлении (компилятор) это абсолютно нормально в том, что касается MyServiceImpl переопределений doB() amp; doC() … однако Eclipse как IDE не уверен, какая реализация будет использоваться, которая поставляется во время выполнения, поэтому не может предоставить вам реализацию doB() при попытке получения из MyService интерфейса.

Надеюсь, это поможет.

Комментарии:

1.Это не совсем точно. Реализует ли класс интерфейс или нет, определяется во время компиляции, а не во время выполнения. Например, public class C { public int compareTo(Object o) { return 0; } public static void main(String[] args) { System.out.println(new C() instanceof Comparable); } } возвращает false , но с C implements Comparable true .

2. Проблема в том, что GeneralServiceImpl.doB() это всего лишь реализация MyService.doB() в MyServiceImpl , поэтому отображение GeneralServiceImpl.doB() как реализации MyService.doB() было бы неправильным. В коде нет MyServiceImpl.doB() того, что может быть показано как реализация. Он существует только с помощью MyServiceImpl extends GeneralServiceImpl implements MyService . Нет ничего, что можно было бы отобразить, даже если это известно из статического анализа кода.

3. Привет, не понял вашу точку зрения из 1-го комментария, и я не могу не согласиться с вашим 2-м комментарием, поскольку GeneralServiceImpl.doB() это единственная реализация MyService.doB() , насколько я вижу из вопроса, это прекрасный пример dynamic polymorphism .

4.Может показаться, что это так, но это не динамический полиморфизм. Если вы переименуете GeneralServiceImpl.doB() , вы получите ошибку компиляции, потому что в MyServiceImpl doB() отсутствует для реализации MyService . Это MyServiceImpl расширение GeneralServiceImpl исправлено в байт-коде. Разрешение привязок выполняется здесь во время компиляции, а не во время выполнения.

5. Привет @howlger, я отредактировал ответ с помощью sceanrio .. Я бы сказал спасибо вашим комментариям, которые сделали ответ более подробным! Надеюсь, теперь мы синхронизированы!

Ответ №2:

У меня это работает.

Протестировано на:

Eclipse IDE для корпоративных разработчиков Java.

Версия: 2019-03 (4.11.0) Идентификатор сборки: 20190314-1200

Я также протестировал его при новой установке (никаких плагинов, отличных от стандартных), и он также работает.

Также протестировано на OSX и Linux (Windows недоступна … извините)

Комментарии:

1. Я использую Eclipse Neon

2. Протестировано то же самое в: Eclipse Java EE IDE для веб-разработчиков. Версия: Neon.3 Release (4.6.3) Идентификатор сборки: 20170314-1500

3. Это работает как на Linux, так и на Mac. Тот же код, что и раньше, тот же положительный результат.

4. @user7294900 Eclipse Neon (4.6) устарел и не поддерживался годами. Пожалуйста, обновитесь до Eclipse 2019-03 (4.11).

5. @howlger Я обновил свой ответ проверенным примером

Ответ №3:

GeneralServiceImpl.doB() не является реализацией MyService.doB() , но в MyServiceImpl используется для реализации MyService.doB() . Следовательно, было бы неправильно отображать GeneralServiceImpl.doB() как реализацию или определение MyService.doB() .

В следующем примере аннотирование FooImpl с @Override приводит к ошибке времени компиляции. Согласно спецификации языка Java 9.6.4.4. это означает, что FooImpl.foo() не реализует и не определяет API.foo() :

 class MyClass extends FooImpl implements API {
    @Override // <- correct
    public void bar() {};
}

interface API {
    void foo();
    void bar();
}

class FooImpl {
    // @Override <- compile error
    public void foo() {}
}
  

Пожалуйста, обратите внимание, что существует больше возможностей для неявной реализации / определения методов, которые не будут показаны Eclipse: например, инструментирование через Java-агент (например, используемый для макетирования объектов) или через декларативную платформу.

Ответ №4:

  1. Когда вы делаете

ctrl наведение курсора мыши

eclipse предоставляет вам 2 варианта:

a. Открытое объявление.

b. Откройте реализацию.

Вам нужно выбрать второй вариант.

  1. Я бы предпочел использовать

‘ctrl T’

чтобы увидеть полную иерархию реализации.

Надеюсь, это поможет.

Комментарии:

1. Я выбираю второй вариант, но тогда он не находит реализаций

2. Разве это не показывало вам MyServiceImpl в раскрывающемся списке? это действительно странно, поскольку я использую эти ярлыки с тех пор, как начал программировать на Java. Можете ли вы убедиться, что вы находитесь в перспективе Java?

3. В обновленном примере становится очевидно, что ‘void doB()’ поступает из GeneralService и MyService. Я сомневаюсь, что это даст вам надежные результаты. Как ожидается, MyServiceImpl решит, что doB () поступает из MyService или GeneralService? На самом деле, doB() в MyServiceImpl взят из GeneralServiceImpl, так что eclipse не перепутан; все наоборот 🙂

4. Я хотел использовать существующий (не spring) метод в новом интерфейсе (spring) без его явного вызова, я перепроектирую классы, но все еще остается вопрос, потому что это работает, т. Е. реализация найдена в реальном времени, но не в eclipse

5. это работает, потому что jvm применяет интеллект, который находит правильную реализацию во время выполнения (не во время компиляции).