В вашем конкретном примере:
Вы объявили centre_x
и centre_y
в качестве переменных экземпляра. Когда ваша программа впервые создает экземпляр GraphicsHierarchy
, порядок создания объекта таков:
ClassLoader загружает класс ... статическим переменным (BOX_WIDTH
, BOX_HEIGHT
) назначаются заданные значения;
Место выделено в куче для экземпляра GraphicsHierarchy
(достаточно места для хранения переменных экземпляра - double
для centre_x
и double
для centre_y
- включая пространство для базы переменные экземпляра класса)
Переменные экземпляра установлены на по умолчанию значения: centre_x
= 0, centre_y
= 0
Вызывается конструктор по умолчанию GraphicsHierarchy
(который не делает ничего, кроме вызова конструктора базового класса - GraphicsProgram
).
Базовый класс будет проходить через шаги 1-4, и когда его законченное выполнение вернется к GraphicsHiearchy
, который теперь оценивает явные инициализаторы переменных экземпляра перед выполнением любых оставшихся операторов конструктора (что в случае конструктора по умолчанию, есть нет).
(дополнительная ссылка на этот процесс http://java.dzone.com/articles/java-object-initialization)
Сказав все это, может показаться, что когда ваш класс GraphicsHierarchy
перейдет к шагу 5 и попытается присвоить значения centre_x
и centre_y
, подсистема, на которую полагаются getWidth
и getHeight
, будет не готов (т.е. окно или холст еще не были созданы, поэтому методы возвращают 0). Но когда вы переместили свои назначения в run и getWidth
/ getHeight
вернули значения, это означало бы, что метод, вызывающий run, сначала прошел необходимые этапы создания окна.
Предложение Этьена де Мартеля в порядке. Это задерживает назначение значений вашего центра до того момента, когда они понадобятся Если вы хотите, вы можете создать метод init и переместить назначения внутри метода init, а затем вызвать init в качестве первого шага выполнения
private void init() {
centre_x = getWidth / 2;
centre_y = getHeight * 0.5;
}
public void run() {
init();
placeGRect();
}
Это почти то же самое, что и предложение Мартела, хотя, если вы обнаружите, что позже у вас есть другой код инициализации, который должен произойти, вы можете выбросить его в том же месте.
Что касается создания гибкого кода, вы можете подумать о переименовании placeGRect
в placeGRects
и передаче в массив точек (или Collection, если хотите) placeGRects(Point[] points)
(вы можете использовать Java.awt.Point или определить свой собственный класс Point)
Таким образом, ваш метод placeGRects упрощается. Он больше не решает, сколько блоков визуализировать (массив, который передается, делает). Он также не определяет, где находятся эти новые блоки (опять же, массив объектов Point). Он просто перебирает размер массива, создает новое поле, добавляет его и устанавливает местоположение.
private Point[] boxPoints;
public void run() {
init();
placeGRects(boxPoints);
}
public void placeGRects(Point[] points) {
for(int i=0;i<points.length;i++) {
GRect b = new GRect(BOX_WIDTH,BOX_HEIGHT);
add(b);
b.setLocation(points[i].x,points[i].y);
}
}
И вы можете поместить инициализацию массива Point в свой новый метод init ().
private void init() {
centre_x = getWidth / 2;
centre_y = getHeight * 0.5;
boxPoints = {new Point(centre_x, 75),new Point(centre_x * 0.5, 250)};
}
Это облегчает понимание и изменение вашего кода при необходимости.