Статический импорт Java
просто экспериментом я обнаружил, что нестатические методы Java переопределяют все одноименные методы в области даже в статическом контексте. Даже без разрешения перегрузки параметров. Как
import java.util.Arrays;
import static java.util.Arrays.toString;
public class A {
public static void bar(Object... args) {
Arrays.toString(args);
toString(args); //toString() in java.lang.Object cannot be applied to (java.lang.Object[])
}
}
Я ничего не могу найти об этом в спецификации. Это жук? Если это не так, есть ли какие-либо причины для реализации такого языка?
UPD: Java 6 не компилируйте этот пример. Вопрос в том-почему?
4 ответов
объяснение простое, хотя это не меняет того факта, что поведение крайне нелогично:
при разрешении вызываемого метода компилятор первым делом находит наименьшую охватывающую область, которая имеет метод с правильным именем. Только тогда приходят другие вещи, такие как разрешение перегрузки и co в игре.
теперь здесь происходит то, что наименьшая охватывающая область, содержащая toString()
метод класса, который наследует от Object
. Поэтому мы останавливаемся там и не ищем дальше. К сожалению, затем компилятор пытается найти наилучшую подгонку методов в данной области и замечает, что он не может вызвать ни один из них и дает ошибку.
что означает никогда статически импортировать методы с именем, идентичным методу в Object, потому что методы, которые, естественно, в области имеют приоритет над статическим импортом (JLS подробно описывает метод shadowing, но для этого проблема я думаю, что гораздо проще просто запомнить это).
Edit: @alf любезно представил правую часть JLS, что описывает вызов метода для тех, кто хочет всю картину. Это довольно сложно, но тогда проблема не проста, так что этого и следовало ожидать.
это не переопределение. Если это сработает,this.toString()
по-прежнему будет доступ к методу A
вместо Arrays.toString
как было бы в случае, если переопределение произошло.
на спецификация языка объясняет, что статический импорт влияет только на разрешение static
методы и типы:
один-статический-импортной декларации D в единице компиляции C пакета P, который импортирует поле с именем N тенями объявления любых статических поле с именем n, импортированное объявлением static-import-on-demand в c, на протяжении c.
объявление одностатического импорта d в блоке компиляции c пакета p, который импортирует метод с именем n с подписью s тени объявление любой статический метод С именем n с подписью s, импортированной объявлением static-import-on-demand в c, на протяжении c.
один-статический-импортной декларации D в единице компиляции C пакета P, который импортирует тип с именем N тени объявления:
- любой статического типа С именем N импортируется объявлением static-import-on-demand в c.
- любой топ-уровня типа (§7.6) с именем n, объявленным в другой единице компиляции (§7.3) p.
- любой введите N импортируется объявлением типа импорт по требованию (§7.5.2) в c. на протяжении c.
статический импорт не тень нестатические методы или внутренние типы.
так toString
не затеняет нестатический метод. С именем toString
может ссылаться на нестатического метода A
, он не может ссылаться на static
метод Arrays
и так toString
привязывается к единственному методу с именем toString
это доступно в области, которая является String toString()
. Этот метод не принимает никаких аргументов, поэтому вы получаете ошибку при компиляции.
15.12.1 объясняет разрешение метода и необходимо было бы полностью переписать, чтобы разрешить затенение недоступных имен методов в static
методы, но не внутри member
методы.
Я предполагаю, что языковые дизайнеры хотели сохранить правила разрешения метода простыми, что означает, что одно и то же имя означает одно и то же, появляется ли оно в static
метод или нет, и единственное, что меняется, это то, что доступно.
Если вы попробуете следовать подобный взгляд кода не будет получить любую ошибку компилятора
import static java.util.Arrays.sort;
public class StaticImport {
public void bar(int... args) {
sort(args); // will call Array.sort
}
}
почему это компилируется и ваш не то, что toString()
(или любой другой метод, определенный в объекте класса) по-прежнему ограничены классом объекта из-за того, что объект является родителем вашего класса. Следовательно, когда компилятор находит соответствующую сигнатуру этих методов из класса Object, он дает ошибку компилятора. В моем примере, так как класс Object не есть sort(int[])
метод, следовательно, компилятор правильно сопоставляет его с статический импорт.
Я не думаю, что это ошибка или что-то отличное от обычного импорта. Например, в случае обычного импорта, если у вас есть частный класс с тем же именем, что и импортированный, импортированный не будет отражен.