Явное совпадение имени Java, имеет одно и то же стирание, и не скрывает другое

17

Я получаю ошибку столкновения этого имени, и я не знаю, как решить проблему. У меня есть два класса, и я использую перегруженный метод «createSensors». Для упрощения здесь приведен код, который порождает проблему:

public abstract class ClassA {
    public static List<Sensor> createSensors(Collection<? extends ClassA> list) {
        List<Sensor> sensors = new ArrayList<Sensor>();
        for (ClassA s : list) {
           sensors.add(s.getSensor());
        }
        return sensors;
    }
}

public abstract class ClassB extends ClassA {
    public static List<Sensor> createSensors(Collection<? extends ClassB> list) {
        List<Sensor> sensors = new ArrayList<Sensor>();
        for (ClassB s : list) {
           sensors.add(s.getSensor());
        }
        return sensors;
   }
}
    
задан user506246 22.12.2012 в 13:47
источник
  • Мне кажется, что вам даже не нужны два метода, так как они делают то же самое. –  Michael Borgwardt 22.12.2012 в 13:57
  • методы используют разные данные –  user506246 22.12.2012 в 14:27
  • , но все, что они используют, это метод getSensor (), который (если он еще не) может быть унаследован или частично интерфейсом, чтобы исключить дублированный код. Это было бы намного лучше, даже если бы столкновение не было проблемой. –  Michael Borgwardt 22.12.2012 в 14:36

3 ответа

6

Общее решение - использовать разные имена. Эти методы могут быть в классах без отношения наследования, поскольку они не являются методами экземпляра.

Как указано, реализация метода в вопросе одинакова (исключение опечатки).

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

    
ответ дан Tom Hawtin - tackline 22.12.2012 в 14:42
  • Предположим, что эти две реализации имели радикально различное поведение, вы все равно получите эту ошибку. Было бы неплохо сосредоточиться на сути вопроса, а не на специфике примера;) –  Ar3s 26.12.2013 в 15:31
  • @ Ar3s Я думаю, что основным ответом является использование разных имен. Но очень часто дженерики считаются необходимыми там, где они на самом деле не такие, как в этом случае, поэтому полезно указать на это. –  Miserable Variable 26.12.2013 в 20:59
11

Общий ответ:

Помимо проблемы одной и той же реализации здесь, суть проблемы заключается в том, что несколько варварский «метод A и метод B имеют одно и то же стирание».

Что делает этот вопрос сложным, так это то, что мы, как правило, не (по крайней мере, не этим утром) много знаем о типе Erasure.

Чтобы сделать это коротко:

  

Параметрические типы выполняют проверку типа во время компиляции (для обеспечения правильности ввода), но забудьте о своих параметрах типа во время выполнения (чтобы избежать генерации базовых методов).

Звучит в то же время просто и загадочно. Лучший способ понять это - обратиться к следующей литературе:

  1. Что такое повторно идентифицируемый тип?
  2. Как и при каких условиях выполняется стирание?
  3. Есть ли у вас какие-либо идеи / примеры того, что это может означать в моей жизни кодирования?
  4. Ну, это странно, и мне это не очень нравится, но мне любопытно, почему они сделали это ...

Надеюсь, что это поможет вам в той мере, в какой это помогло мне.

Конкретный ответ:

В вашем случае

public abstract class ClassA {
    public static List<Sensor> createSensors(Collection<? extends ClassA> list) {
        //do stuff
    }
}

public abstract class ClassB extends ClassA {
    public static List<Sensor> createSensors(Collection<? extends ClassB> list) {
        //do other stuff
   }
}

будет преобразован javac в

public abstract class ClassA {
    public static List createSensors(Collection list) {
        //do stuff
    }
}

public abstract class ClassB extends ClassA {
    public static List createSensors(Collection list) {
        //do other stuff
   }
}

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

Хватит этой проблемы, как ее решить? Вы можете выполнить один из следующих способов:

  • Используйте разные имена: createASensors и createBSensors этот подход является наиболее очевидным, но выглядит немного менее изящным.

  • Добавить параметр: createSensors(Collection<? extends ClassA> list, ClassA typeDefiner) этот подход может показаться варварским, но немного менее изящным, но тот, который используется в java.util.List для метода <T> T[] toArray(T[] a) .

ответ дан Ar3s 26.12.2013 в 18:09
  • Erasure (знание того, что в целом предполагается заголовком вопроса) типов времени выполнения не имеет отношения к этому вопросу, так как это касается выбора метода link-time. / Этот метод toArray предшествует дженерикам тремя релизами. –  Tom Hawtin - tackline 26.12.2013 в 18:30
  • Ваш ответ объясняет это очень хорошо. Но мне было интересно, можете ли вы также объяснить, почему компилятор ведет себя так, и почему нам просто не позволено называть методы их фактическим классом, чтобы их отличать; ClassA.createSensors (...) ClassB.createSensors (...) –  Foumpie 14.06.2017 в 11:27
-1

Проверьте настройки проекта и версию компилятора проекта. Щелкните правой кнопкой мыши по проекту - & gt; Свойства - & gt; Компилятор Java. Убедитесь, что настройка соответствия обновлена. У меня была эта проблема, когда параметры соответствия были установлены на 1.4 вместо 1.6

    
ответ дан Asanka Siriwardena 05.11.2014 в 10:35
  • Параметры компилятора не имеют ничего общего с этой ошибкой. –  Lucas Holt 25.01.2016 в 18:54