2016-01-31 3 views
1

Я думал, что понял концепцию затенения. Но этот код заставил меня задуматься:Тень/Область переменных

public class Counter { 
int count = 0; 

public void inc() { 
    count++; 
} 

public int getCount() { 
    return count; 
} 

}

class StepCounter extends Counter { 
int count = 0; 
int step = 1; 

public StepCounter(int step) { 
    this.step = step; 
} 

public void inc() { 
    count += step; 
} 

}

StepCounter sc = new StepCounter(2); 
    sc.inc(); 
    sc.inc(); 
    System.out.println(sc.getCount()); 
    System.out.println(sc.count); 

Так в основном статический тип скандий StepCounter. Счетчик увеличивается в два раза, поэтому после первых двух команд он равен 4. Мой счетчик Variable не является частным, он является закрытым пакетом (поскольку я не указал на него видимость). Так что, если я вызываю метод .getCount() на sc, он сначала ищет его в StepCounter. Его нет, поэтому он идет к Counter. Здесь он находит метод getCount(). этот способ возвращает счет. Если счет был статичным или закрытым, я бы понял, почему он возвращает 0. Но почему он возвращает 0 в этом случае? Даже если я сделал счетчик переменных в StepCounter, результат будет равен 0.

+5

Поскольку переменные-члены не являются полиморфными. Counter.getCount всегда возвращает Counter.count. –

+0

Связанный: http://stackoverflow.com/questions/32422923/why-does-java-bind-variables-at-compile-time – manouti

+0

Также поле здесь не затенено. Он скрыт. – manouti

ответ

1

Вы всегда должны избегать затенения как можно больше, это может привести к серьезным непредсказуемым поведением для вашего кода. Что вам не хватает здесь, это концепция изменения переменных в Java. count является лишь сокращением для this.count. Таким образом, учитывая ваш код, что распознаватель делает здесь, после вызова метода getCounter(), является:

  1. Попробуйте решить getCounter() как экземпляр StepCounter класса
  2. терпит неудачу, попытайтесь найти класс предков
  3. Ближайший предок Counter, поэтому контекст переключается Counter класса
  4. Try разрешить getCounter() в Counter класса
  5. Метод найден, попытаться решить значение count
  6. getCounter() не является статическим, поэтому count на самом деле this.count (если getCounter() должны были быть статическим, было бы Counter.count)
  7. this.count решает оценить 0 в рамках экземпляра Counter класса
  8. 0 возвращается
+0

Это вне области действия конструктора относится к текущему объекту, правильно? Итак, this.getClass() - это StepCounter, поэтому у меня все еще есть проблемы с выводом на экран этапа 7 .. – InDaPond

+0

'getClass()' дает ссылку для класса, на котором был создан ваш экземпляр. В вашем примере у вас есть два отдельных значения для свойства 'count' в созданном вами экземпляре' sc'. Один в контексте класса «StepCounter» и один в контексте класса «Counter». Вы можете попробовать это, просто добавив эту строку в конец вашего кода: 'System.out.println (((Counter) sc) .count);'. 'this' в объеме' getCounter() 'метод принимает значение' (Counter) this'. –

+0

Большое спасибо! Поэтому всякий раз, когда я пишу это как ссылку на объект, он равен записи (Cast of class, я пишу это в) this. Это правильно? – InDaPond

1

В Java поля не могут быть переопределены. Только методы могут быть переопределены. Поэтому наличие переменной «count» в StepCounter не переопределяет поле «count» в суперкомпьютере «Counter». Он просто создает другое поле. Однако метод getCount возвращает значение поля «count» в суперклассе. Чтобы желаемая функциональность должна была переопределить метод getCount в классе StepCounter.

+0

У моего объекта есть динамический счетчик типов. Теперь метод getCount() говорит: «Верните свое поле с именем count». Разве он не должен выглядеть в своем собственном объеме (В)? – InDaPond

+0

Поля @InDaPond никогда не могут быть переопределены, поэтому, когда метод getCount выполняется, он видит поле «count», определенное только в суперклассе –

2

getCount()может доступ только поле counter ТНТ было определить d в родительском классе. Этот класс разрешен в компиляции времени родительского класса. Нет копия метода getCounter() у ребенка.

В дочернем классе, вы можете использовать

Counter.this.count 

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

Смежные вопросы