Статический импорт 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[]) метод, следовательно, компилятор правильно сопоставляет его с статический импорт.


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