Статьи

Уважение к типу возврата для перегрузки метода

Впервые я познакомился с Java после нескольких лет опыта работы с C ++, и поэтому мне показалось естественным, когда я узнал, что Java не допускает перегрузку методов в зависимости от типа возвращаемого значения . Раздел « Определение методов » урока « Классы и объекты» в Учебном руководстве по языку Java гласит: «Компилятор не учитывает тип возвращаемого значения при различении методов, поэтому вы не можете объявить два метода с одинаковой сигнатурой, даже если они имеют другой тип возвращаемого значения».

Действительно, как Vinit Joglekar уже отметил , «Это общепринятый факт , что Java не поддерживает на основе обратного типа метода перегрузки.» StackOverflow поток Java — почему нет возврата типа метода , основанной перегрузки? объясняет, почему это так в Java . Учитывая это, я был удивлен, когда коллега показал мне фрагмент кода с двумя перегруженными методами с одной и той же сигнатурой времени выполнения, скомпилированной в JDK 6, при условии, что возвращаемые типы различаются.

Следующий класс успешно компилируется с JDK 6, но не с JDK 7.

Компилируется в JDK 6, но не в JDK 7

package examples.dustin;

import java.util.Collection;

/**
 * Simple example that breaks in Java SE 7, but not in Java SE 6.
 * 
 * @author Dustin
 */
public class Main
{
   public static String[] collectionToArray(final Collection<String> strings)
   {
      return new String[] { "five" };
   }

   public static int[] collectionToArray(final Collection<Integer> integers)
   {
      return new int[] { 5 };
   }
   
   /**
    * Main function.
    * 
    * @param arguments The command line arguments; none expected.
    */
   public static void main(String[] arguments)
   {
   }
}

Как описано в Анжелике Лангер , Что такое перегрузка метода? вышеуказанный код не должен компилироваться. Это не в Java SE 7. В NetBeans 7.1 это не так. Или, точнее, это смешанная сумка.

Как показано на снимке экрана ниже, NetBeans 7.1 создает исходный код выше тонкой, как показано в окне вывода, когда версия Java, связанная с проектом, — Java SE 6. Однако редактор NetBeans показывает красные волнистые линии, указывающие на ошибку компилятора. Следующее изображение показывает, что сообщение об ошибке.

Хотя NetBeans 7.1 может создавать код, показанный выше, когда он является частью проекта, связанного с Java SE 6 (в данном случае это обновление 31), редактор кода по-прежнему сообщает об ошибке, показанной выше. Это связано с тем, что NetBeans использует внутреннюю версию компилятора Java, отличную от той, которая явно связана с редактируемым проектом. Если я изменю версию Java, связанную с проектом NetBeans, на приведенный выше исходный код, он больше не будет встроен в NetBeans. Это показано далее.

Есть несколько интересных вещей об этой ошибке. Во-первых, тот факт, что этот код прекрасно компилируется в Java SE 6, но адресуется и не компилируется в Java SE 7, означает, что код, работающий в Java SE 6, может не работать, когда база кода перемещается в Java SE 7. Я скачал последнюю версию JDK 6 ( Java SE 6 Update 31 ) и подтвердил, что оригинальный код, показанный выше, все еще собирается в Java SE 6. Он не встраивается в Java SE 7.

Существуют другие версии приведенного выше кода, которые не создаются в Java SE 6 или Java SE 7. Например, если приведенный выше код изменяется так, что методы возвращают один и тот же тип, код не создается даже в Java SE 6. Аналогичным образом, если параметры Collection для двух перегруженных методов включают «необработанную» коллекцию (без параметризованного типа), она также не будет компилироваться в Java SE 6. Конечно, даже если возвращаемые типы различны, если одинаковые параметризованные типы Collection передаются обоим перегруженным методам, даже Java SE 6 не скомпилирует это. Эти три ситуации изображены на следующих трех снимках экрана.

Код, который создается в Java SE 6, но не в Java SE 7, должен иметь перегруженные методы, которые различаются как по типам возвращаемых данных, так и по параметризованным типам коллекций, которые составляют параметры их методов. Не имеет значения, соответствует ли данный возвращаемый тип или относится к параметризованному типу параметра метода, если они различаются. Если возвращаемые типы совпадают, Java SE 6 обнаруживает ошибку компилятора. Java SE 6 также обнаруживает ошибку, если стертые параметры сводятся к одной и той же коллекции после стирания, и возвращаемые типы не отличаются.

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

Поскольку NetBeans 7.1 использует свой собственный внутренний Java-компилятор для редактора кода, можно задаться вопросом, означает ли это, что возможности Java 7 могут быть скрыты и будут работать в IDE, но затем не будут создаваться при попытке из командной строки или когда явно встроены в IDE. Следующий снимок экрана демонстрирует, почему это не так. В этом снимке в коде содержится особая функция Java 7, и NetBeans 7.1 предупреждает, что она несовместима с исходной настройкой Java 1.6.

Ошибка 6182950 ( алгоритм столкновения методов не должен зависеть от типа возвращаемого значения ) устраняет проблему в JDK 7, но не в JDK 6. Связанная ошибка — Ошибка 6730568 («Стирание типа влияет на возвращаемые типы + параметры типа»). Три дополнительных ссылки, которые предоставляют достаточно больше сведений о фоновом режиме, — это два потока StackOverflow ( различное поведение между Java 5 и 6 при перегрузке обобщенных методов и какова концепция стирания в обобщениях в java? ) И запись Учебника Java по типу Erasure .

Коллега, который показал мне эту проблему, осознал ее существование, потому что NetBeans 7.1 сообщил о «конфликте имен … такое же стирание», даже когда он работал с кодом Java SE 6. Это обнаружение было «случайным» из-за более новой версии NetBeans, использующей компилятор Java SE 7 для внутреннего использования, но он приветствовал возможность исправить проблему сейчас, а не при переходе на Java SE 7.

Я нашел эту проблему достойной публикации в блоге, потому что она предоставляет предупреждение об ошибке, которая может уже быть в некоторых базах кода Java SE 6, но станет слишком очевидной, когда база кода будет перемещена в Java SE 7. Я также опубликовал это потому, что я думаю, что важно знать, что современные версии NetBeans используют внутренний компилятор, который может иметь версию, отличную от компилятора, который разработчик явно связал со своим проектом NetBeans.