Я объявил private static double fd
, а затем снова объявил double fd
внутри main(). Почему я могу скомпилировать и запустить его успешно?
public class HelloWorld {
private static double fd = 1.0;
public static void main(String[] args){
System.out.println(fd); //1.0
double fd = 2.0;
System.out.println(fd); //2.0
}
}
И просто для развлечения и путаницы вы можете объявить локальный fd
с типом, отличным от статического fd
. А также для еще большего удовольствия вы можете использовать fd
в собственном инициализаторе: double fd = fd = 2.0;
.
Ответ таков: потому что разработчики Java решили сделать это возможным.
@JBNizet, теперь, когда вы подняли этот вопрос, я вижу, что вы правы. Я считаю, что это наследие C/C++, но они могли просто решить, что это ошибка компилятора. Итак, учитывая сомнительную полезность и склонность к ошибкам этой «функции», почему было решено разработать спецификации именно таким образом?
Потому что это чрезвычайно полезно, например, иметь возможность делать такие вещи, как this.name = name
.
Переменная фд имеет область действия функции, подумайте, компилятор сначала проверяет ближайшую к ней область, а затем, если он не находит там, он пытается проверить глобальную область видимости, если он нашел что-то в локальной области видимости, он напечатает это, или else переходит к проверке другой области.
Это не синтаксическая ошибка (хотя это, вероятно, приведет к логической ошибке, багу). Компилятор без проблем скомпилирует этот код. Второе объявление double fd создает локальную переменную для основного метода. Область действия этой переменной начинается с ее объявления и заканчивается в конце блока (как и для всех локальных переменных). Поэтому следующий оператор использует локальную переменную, а не переменную экземпляра.
Локальная переменная больше не будет содержать значение после возврата метода. Переменная экземпляра не будет изменена.
Подсказка: представьте, что операторы смотрят «вверх» из своего собственного местоположения, чтобы найти каждую из своих переменных. Они могут смотреть за пределы своего «стеклянного ящика» в любом направлении, если им не удается найти переменную внутри собственного метода.
Почти всегда ошибочно использовать одно и то же имя для переменной экземпляра и для локальной переменной. Но это не синтаксическая ошибка, поэтому компилятор вас не предупредит.
как написал @JB Nizet: это дизайнерское решение создателей языка. из-за этого компилятор мог выдает ошибку. и, учитывая сомнительную полезность и склонность к ошибкам этой «функции», может ли она иметь?
Из раздела JLS Объем декларации:
The scope of a declaration is the region of the program within which the entity declared by the declaration can be referred to using a simple name, provided it is not shadowed.
Из раздела JLS Затенение:
Some declarations may be shadowed in part of their scope by another declaration of the same name, in which case a simple name cannot be used to refer to the declared entity.
Это означает, что вы не можете использовать простое имя (df
) для ссылки на переменную уровня класса df
, потому что она затенена локальной переменной df
. Но есть еще две переменные, и вы можете использовать статическую переменную с именем класса:
public static void main(String[] args){
System.out.println(fd); //1.0
double fd = 2.0;
System.out.println(fd); //2.0
System.out.println(HelloWorld.fd);
}
ты не. вы объявляете локальную переменную, которая имеет то же имя, что и ваша статическая переменная