T.M. SoftStudio

feci quod potui, faciant meliora potentes

Купить полную версию курса "Введение в вычисления с Java" (русскоязычная версия, лекции, тесты, лабораторные работы)

Введение в вычисления с Java. Объектно-ориентированное программирование

Неделя 3

Лекция 17

Пример Car2

В предыдущем примере автомобиля, методы moveCar и turnCar просто распечатывали сообщение на экране о том, что методы должны делать, вместо выполнения реальных действий.

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

И мы даем этому классу новое имя Car2.

У нас еще есть экземпляр переменной для хранения информации о владельце, как и раньше.

То, что мы хотим сделать, это использовать некоторые фотографии автомобилей для представления различных экземпляров объекта Car.

Так вот, вместо того чтобы использовать только одну переменную экземпляра владельца, у нас также теперь есть еще одна переменная экземпляра, которая имеет тип ColorImage (своего рода объект холста, о котором мы только что говорили), и давайте, теперь, инициализируем изображение автомобиля по умолчанию как Car1.png.

Кроме того, мы хотим описать больше полезных свойств об автомобилях в этом классе.

Люди в наше время любят покупать экологически чистые автомобили. Поэтому полезной информацией является расход топлива.

Переменная экземпляра gasMileage типа double объявляется для этой цели, и предполагается, что значение переменной представляет собой количество топлива в литрах, используемых на каждые 100 км.

Наконец, мы хотим знать, сколько бензина в баке. В то время как предыдущие поля были относительно стабильными, это значение часто изменяется время от времени и отличается для различных экземпляров автомобилей.

Эта коллекция переменных экземпляра дает абстрактное описание объекта автомобиля – его владельца, его внешний вид, его эффективность расхода топлива и внутреннее количество топлива в баке.

Каждый раз, когда новый объект автомобиля создается, необходимо выделять объем памяти для хранения всей этой информации.

Давайте взглянем на конструкторы для Car2 объекта.

Обратите внимание, что первый конструктор такой же, как и раньше, за исключением того, что именем конструктора является Car2, так как имя класса в настоящее время Car2.

Конструктор, который не имеет параметров, просто использует все настройки по умолчанию.

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

Как и второй конструктор в предыдущем примере, 2-й конструктор здесь имеет один параметр типа String.

Первое выражение в теле конструктора является таким же, как прежде, которое изменяет значение владельца на значение, заданное параметром nameOfOwner.

Мы добавили второе выражение здесь, которое изменяет carImage на новое изображение.

Ключевое слово new здесь показывает, что создается новый объект типа ColorImage.

Поскольку ни один параметр не предоставляется ColorImage, пользователю будет предложено выбрать существующее изображение из папки.

Третий конструктор объявляется здесь. Поскольку gasMileage может измениться, так как автомобиль стареет, чтобы не вводить в заблуждение клиента, который покупает подержанную машину, конструктор позволит gasMileage измениться.

Этот конструктор принимает два параметра, один типа String, другой типа double.

В дополнение к тому, что делается во 2-ом конструкторе, значение переменной gasMileage экземпляра изменяется на newGasMileage при создании нового объекта Сar2, который создается с помощью этого конструктора.

Давайте теперь посмотрим на методы Сar2.

У нас были методы перемещения и поворота автомобиля, и они просто распечатывали сообщение на экране о том, что эти методы должны делать.

Вместо того чтобы просто распечатать сообщение, модифицированный метод на самом деле двигает автомобиль на холсте из текущего положения вперед.

Текущее положение получается методом getX для объекта carImage с помощью оператора точки.

А расстояние перемещения указывается в качестве параметра.

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

Мы сначала вычислим количество топлива, потребляемого на это расстояние.

А затем количество топлива, оставшегося в баке теперь может быть обновлено путем вычитания gasUsed из значения gasInTank.

Результат вычислений выводится на консоль. Обратите внимание, что параметр расстояния может принимать как положительные, так и отрицательные значения, таким образом, метод позаботился о том, как двигаться вперед, а также назад, когда расстояние отрицательно.

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

Текущая ориентация получается методом getRotation для объекта carImage с помощью оператора точки.

Так как мы использовали некоторое количество топлива, метод добавляется здесь, чтобы мы могли пополнить бензобак.

Давайте назовем этот метод addGas.

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

Помните, что мы вычислили gasUsed в методе перемещения. В выражении внутри метода addGas добавим значение gasUsed к gasInTank, а затем присвоим результат обратно к переменной gasInTank.

Как вы думаете, это будет работать?

То, что вы обнаружите, это компилятор будет выдавать ошибку: "Невозможно найти символ – переменную gasUsed".

Почему это так? Это потому, что есть очень важное понятие – область видимости переменных, которое у нас еще не обсуждалось.

В принципе, видимостью переменной является блок кода, где переменная может быть использована.

В случае gasUsed, она называется локальной переменной, и она имеет смысл только в рамках метода moveForward.

Так любая ссылка на нее вне метода moveForward вызовет ошибку.

Метод moveForward можно было бы вызвать много раз, и переменная gasUsed используется только как временное хранилище для хранения конкретной поездки, и она принимает разные значения в других поездках.

В некотором смысле, это как кратковременная память. Мы возвратимся к правилам области видимости в деталях в следующей лекции.

Давайте теперь просто изменим метод addGas, что он был методом с одним параметром gasToAdd, который дает количество топлива для добавления и выражение внутри метода addGas обновит количество топлива в баке соответственно.

Car2 Demo

Откроем среду BlueJ и загрузим Сar2.

Мы увидим определение Сar2. Здесь у нас есть объявления переменных экземпляра, конструкторы, а также методы.

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

Давайте теперь скомпилируем программу.

Oops! Существует ошибка.

Как я уже говорил, это потому, что переменная, gasUsed, не определена внутри метода addGas.

Если мы уберем это и используем правильную версию метода, программа компилируется без ошибок.

Давайте создадим экземпляр объекта Сar2 с первым конструктором, используя настройки по умолчанию.

Мы сначала вызовем метод Сar2Demo так, чтобы изображение автомобиля отобразилось на холсте.

Затем мы можем выбрать метод, чтобы двигаться вперед. Давайте двигаться вперед на 200 единиц.

Обратите внимание, что автомобиль перемещается, и консоль также отображает, что 0,2 л бензина было использовано и количество топлива, оставшегося в баке теперь 9.8 вместо 10.

Теперь мы можем вызвать метод addGas, чтобы увидеть, может ли он на самом деле изменить переменную gasInTank экземпляра, скажем при добавлении 10 L.

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

Здесь мы увидим, что gasInTank теперь 19,8, а не просто 9.8, как и прежде.

Давайте взглянем на метод makeTurn и повернем машину, скажем на 90 градусов. Автомобиль вращается, как ожидалось.

Все до сих пор кажется прекрасным. Давайте вернемся к методу moveForward и переместить автомобиль на 100 единиц.

Он движется, но, вероятно, не так, как автомобиль должен был бы продвинуться вперед.

Я хотел бы, чтобы вы думали о том, как решить эту проблему так, чтобы автомобиль двигался вперед  в том же направлении, что и ориентация автомобиля.

Если вернуться к автомобилю, вы можете попробовать другие конструкторы, введя имена файлов и так далее.