С точки зрения идеи об отношении подкласса и суперкласса, давайте посмотрим, как класс сберегательного счета может быть реализован как подкласс класса банковского счета, который мы обсуждали раньше.
Вот определение класса BankAccount, где объявляются две переменные экземпляра balance и owner, и два конструктора, один без параметров, а другой с двумя параметрами.
Обратите внимание, что переменные экземпляра объявлены как private.
Я вернусь к private полям подкласса позже.
И есть три метода, а именно, deposit, withdraw и getBalance.
Все это также полезные методы для класса SavingsAccount, который я собираюсь обсудить.
Вот реализация SavingsAccount класса в Java.
Ключевое слово extends используется для создания подкласса, который наследует поля и методы от существующего класса, который становится суперклассом.
Подклассу дано имя SavingsAccount, который расширяет BankAccount.
Подкласс наследует все члены, включая поля и методы из своего суперкласса.
Одна дополнительная переменная InterestRate экземпляра объявлена в подклассе SavingsAccount, и он также наследует переменные экземпляра balance и owner от BankAccount.
Я поговорю о методах позже.
Конструкторы обрабатываются по-разному, они не наследуются подклассами, но конструктор суперкласса может быть вызван из подкласса.
Здесь объявляется конструктор для SavingsAccount.
Он принимает три параметра, в дополнение к initialBalace и name, как в одном из конструкторов BankAccount, третий параметр является double параметром rate, который используется для инициализации процентной ставки.
Конструктор подкласса может вызывать конструктор суперкласса с помощью ключевого слова super.
Это вызов конструктора с двумя параметрами из BankAccount.
Обратите внимание, что синтаксис вызова конструктора суперкласса – это использование ключевого слова super, после которого следует список параметров в скобках.
Список может быть пустым, если вызывается конструктор по умолчанию суперкласса.
Если конструктор не определен явно в подклассе, конструктор суперкласса по умолчанию без аргументов будет использоваться для подкласса.
Ошибка компиляции возникает, если суперкласс не имеет конструктора по умолчанию без аргументов.
Я проиллюстрирую это в демо, после того как мы завершим определение SavingsAccount.
Это реализация метода вычисления сложных процентов.
Метод называется compoundInterest, который принимает один аргумент duration типа int, который дает число раз, сколько должны быть вычислены проценты.
Здесь используется цикл for, так как мы получаем переменную duration, которая говорит нам точно, сколько раз будут вычисляться проценты.
Если у вас есть время, вы можете подумать об альтернативных реализациях, использующих while или do-while цикл.
Каждый раз внутри цикла текущий баланс извлекается с помощью метода getBalance.
Мы не можем получить доступ к переменной экземпляра balance в BankAccount напрямую, потому что она объявлена как private.
Конструкторы или методы из подкласса имеют не больше прав на private поля суперкласса, чем любые другие методы.
То есть, если метод в SavingsAccount хочет получить доступ к балансу, он должен получить доступ к нему с помощью public метода в BankAccount, в данном случае, getBalance.
Проценты, начисленные за i-й период, получаются умножением текущего баланса на InterestRate, который задан в качестве параметра.
Важным шагом здесь является использование метода deposit, определенным в BankAccount, чтобы внести или добавить новые проценты к текущему балансу.
Важно отметить, что метод deposit наследуется от суперкласса BankAccount и модификация, произведенная методом deposit, является переменной экземпляра balance, которая также наследуется от BankAccount.
Таким образом, баланс теперь обновляется, чтобы включить новые начисленные проценты, и в следующий раз через цикл, метод getBalance будет получать обновленный баланс, и таким образом, вычисляются составные проценты.
Я хочу отметить, также, как составные проценты могут быть вычислены.
Используется единая формула:
P * (1 + r)^n, где Р является базой, r это процентная ставка и n это число раз, сколько проценты начисляются.
Не волнуйтесь, если вы не знаете или не помните эту формулу, потому что даже если вы бы узнали об ней, вы, вероятно, забыли бы о том, как она была получена.
Но если вы посмотрите на то, как составные проценты вычисляются с использованием for цикла, это, будет вероятно, более интуитивным, чем вычисление, следующее тому, как составные проценты определяются.
Обратите внимание также, что существует сеттер метод setInterestRate для установки переменной InterestRate экземпляра в новое значение, указанное параметром rate.
Давайте откроем IDEA, чтобы посмотреть на демо программу SavingsAccount.
Откроем проект BankAccountEx в среде IDEA.
Как вы можете видеть, здесь есть класс BankAccount, и есть класс SavingsAccount.
Есть и другие классы, которые я буду обсуждать позже.
Если вы откроете BankAccount, это тот класс BankAccount, который мы определили ранее.
И вот класс SavingsAccount, который мы только что описали.
Как вы можете видеть, SavingsAccount расширяет BackAccount.
SavingsAccount также объявляет переменную InterestRate экземпляра.
Там также есть один инструктор и два метода, compoundInterest, и сеттер-метод setInterestRate.
Если мы скомпилируем этот метод, мы не увидим никаких синтаксических ошибок.
В классе SavingsAccount представлен один конструктор.
Этот конструктор имеет три параметра, initialBalance, name и rate, как указано в конструкторе.
Обратите внимание, что здесь нет конструктора по умолчанию без аргументов.
Давайте попробуем создать экземпляр класса с помощью этого конструктора, и значений трех параметров, для initialBalance введем, скажем, 1000, а затем имя владельца, и процентную ставку, в обсуждении мы говорили о 10%, и 10% будет 0,1.
Мы можем вычислить составные проценты, вызвав метод compoundInterest.
Скажем, если мы установим срок до 10 лет, Вы можете увидеть эти новые балансы по состоянию на конец каждого года.
Теперь давайте вернемся к BankAccount и попытаемся посмотреть на влияние различных способов определения конструктора.
Давайте сначала попробуем удалить определение конструктора в SavingsAccount.
Теперь, если вы пойдете в SavingsAccount, вы обнаружите, что теперь доступен конструктор по умолчанию.
Этот конструктор на самом деле конструктор от суперкласса BankAccount.
Если мы создаем экземпляр, используя этот конструктор, вы увидите, что баланс установлен в 0.0, и владельцу было дано имя NoName.
Если вы пойдете в BankAccount, вы увидите, что конструктор по умолчанию в BankAccount использует это начальное значение для баланса, а также имя владельца NoName.
Давайте вернем конструктор SavingsAccount.
Если мы также создадим здесь, в классе SavingsAccount, конструктор по умолчанию, мы можем скомпилировать программу, и не будет синтаксических ошибок.
Теперь вы можете видеть, что здесь доступны конструктор по умолчанию и конструктор с тремя параметрами.
На самом деле, если вы хотите быть более точным,
Если вы хотите вызвать конструктор по умолчанию суперкласса, вы также можете сделать это, указав super и пустой список параметров внутри скобок.
Программа SavingsAccountDemo в основном состоит только из main метода.
Помните, что main метод является точкой входа для всех программ Java?
Здесь мы создали сберегательный счет с помощью конструктора, и мы указали начальный баланс 1000, Джона как владельца счета, и процентную ставку 10%.
Обратите внимание, что в BankAccount переменную экземпляра balance можно получить с помощью метода getBalance, но мы еще не создали метод получения имени владельца.
Поскольку владелец объявлен как private, мы не можем получить доступ к имени владельца в классе SavingsAccount.
Вы можете подумать о том, как определить метод получения имени владельца.
После установки сберегательного счета с именем, мы пытаемся извлечь первоначальный баланс из этого объекта.
То, что мы пытаемся сделать здесь, заключается в попытке сравнить два различных способа при вычислении составных процентов.
Первый заключается в использовании метода compoundInterest, который мы определили для SavingsAccount.
Помните, что мы используем цикл при вычислении составных процентов.
Другой способ заключается в вычислении составных процентов с использованием формулы.
Это формула, которую я кратко уже обсудил.
Чтобы вычислить определенное число в n степени, можно использовать метод pow в библиотеке Math.
Таким образом, здесь приведена реализация этой формулы.
Вы можете видеть, после того как мы вычислили составные проценты, используя метод compoundInterest, мы показываем результат, используя вывод IO.outputln.
Мы также вычислили составные проценты по формуле, а затем выводим результат.
Вы можете видеть, что эти два числа в основном одинаковые.
Единственное различие состоит в неточности числа с плавающей точкой.
Давайте посмотрим на другой подкласс класса BankAccount, который мы написали здесь.
Он называется CheckingAccount.
CheckingAccount является типом счета, который не зарабатывает проценты.
Существует также плата за каждое снятие с CheckingAccount, в то время как нет комиссии для внесения денег на счет.
И CheckingAccount расширяет BankAccount.
Здесь есть переменная экземпляра, представляющая комиссию, которая будет взиматься за каждый чек снятия денег со счета.
Существует один конструктор, снова с 3 параметрами.
Первый параметр это initialBalance, второй это имя владельца, и третий параметр, это комиссия, чтобы установить значение переменной perChequeFee экземпляра.
Существует только один метод в классе CheckingAccount.
Заметьте, что мы определяем метод withdraw, который имеет то же имя, что и метод withdraw в BankAccount.
Что делает этот метод, это забирает деньги из CheckingAccount.
Но разница здесь в том, что вместо того, чтобы просто снять wAmount, мы должны добавить комиссию perChequeFee в сумму, в дополнение к wAmount.
Поскольку withdraw в CheckingAccount имеет то же имя, как метод withdraw в суперклассе BankAccount, если опустить super, вы вызываете метод с таким же именем внутри метода.
Это называется рекурсия. Я буду говорить о рекурсии позже.
Если вы не будете осторожны с рекурсией, это может привести к бесконечному циклу.
Это означает, что этот метод никогда не завершится.
Таким образом, вместо того, чтобы вызвать метод withdraw класса CheckingAccount, мы можем указать, что мы хотим вызвать метод withdraw в BankAccount, суперклассе, указав ключевое слово super, а затем оператор точки.
Используя этот способ, будет вызываться метод withdraw в BankAccount, вместо метода withdraw, определенного здесь, внутри CheckingAccount.
При компиляции этого метода нет ошибок.
Вы можете создать экземпляр, введя initialBalance 1000, имя, и комиссию 2 рубля.
Этот экземпляр унаследовал три метода, определенных в BankAccount, deposit, getBalance и withdraw.
При попытке вызвать метод withdraw, скажем, если вы хотите снять 100 рублей,
Вместо того чтобы получить баланс 900, обновленный баланс будет 898 рублей, потому что в дополнение к 100 рублям, которые вы снимаете, плата в 2 рубля также добавляется к сумме вывода.
Так что, если вы попытаетесь внести обратно 100 рублей на счет, заметьте, что мы используем метод deposit, который наследуется от класса BankAccount.
Так что, если Вы захотите внести 100 рублей назад, вы получите баланс на 2 рубля меньше, потому что 2 дополнительных рубля были сняты с чеком.
Итак, программа CheckingAccountDemo создает объект класса CheckingAccount.
Мы также определяем как вносимую сумму, так и сумму снятия.
У нас есть еще одна переменная типа character, которая называется option.
То, что вы видите здесь, в теле main метода, это do-while цикл.
То, что мы пытаемся сделать, это позволить пользователю продолжать делать различные транзакции, в том числе вложение денег, снятие денег, проверку баланса счета и выйти из цикла.
Как вы можете видеть, это организовано с помощью do-while цикла, и do-while цикл будет продолжаться до тех пор, пока пользователь хочет сделать еще один ввод, вывод или проверить баланс.
Если пользователь вводит любой другой вариант option в виде символа, он выйдет из цикла.
Если вы посмотрите на цикл более тщательно, он сначала спрашивает пользователя тип сделки, которую он хочет осуществить.
И пользователь должен ввести символ.
Заметьте, что переменная option типа CHAR.
Для переменной char в Java, она определяется внутри одинарных кавычек.
Это важно помнить, потому что это отличается от строки символов.
Как вы можете видеть, символьные строки заключены в двойные кавычки, в то время как символ заключен в одинарные кавычки.
Таким образом, после ввода option пользователем, выражение switch будет проверять опцию, а затем выполнит соответствующие действия соответствующим образом с помощью case выражения.
В случае, когда пользователь вводит D для депозита, у пользователя спросят сумму денег, которую нужно внести на счет.
Здесь на самом деле получается сумма вносимых денег с помощью метода inputDouble.
Вносимая сумма будет присвоена переменной dAmount.
И далее будет вызываться метод deposit.
Заметьте, что метод deposit здесь хотя и принадлежит объекту chequeAccount, он фактически наследуется от класса BankAccount.
И это та сумма, которая внесется на счет.
И помните, что для выражения switch важно поставить break, в противном случае выполнение будет просто проходить через каждый из этих случаев.
В случае ввода символа W, клиент хочет сделать вывод.
Далее получаются входные данные с помощью класса IO.
Сумма изъятия присваивается переменной wAmount.
Теперь, здесь вызывается метод withdraw, withdraw метод, определенный в CheckingAccount.
Концепция в том, что, если метод с тем же именем определен в подклассе, он будет переопределять тот метод, что в суперклассе.
Таким образом, в этом случае, если вы посмотрите на класс CheckingAccount, это withdrawn метод.
И тогда для варианта B, идет просто вызов метода getBalance.
Мы должны использовать метод getBalance, чтобы получить переменную экземпляра balance от BankAccount, потому что там она объявляется как private.
Здесь нет действия для случая по умолчанию.
Поэтому этот цикл будет просто продолжаться так долго, как пользователь будет вводить D, W или B.
Цикл здесь на самом деле будет прекращаться при вводе другого символа, не D, W или B.
Запустим эту программу.
Здесь вы можете увидеть приглашение на ввод.
Вы должны ввести один из этих вариантов.
Скажем, мы введем D, и сумму вклада, скажем 100 рублей.
Ну, мы действительно не знаем, была ли на самом деле сумма переведена на депозит.
Так что, если мы вводим опцию B, что означает получить баланс, вы можете увидеть, что сумма в 100 рублей была добавлена к исходному балансу 1000.
Если мы хотим сделать вывод, скажем 100 рублей.
И опять же, если вы хотите проверить баланс, вы должны ввести опцию B.
Вы можете видеть, что баланс теперь составляет 998 рублей.
Таким образом, вместо того, чтобы просто вычесть 100 рублей по сравнению с предыдущим балансом, 2 дополнительных рубля были сняты с баланса, потому что есть плата за каждое снятие.
И тогда мы можем выйти из программы, просто введя E.
Существует также благодарственное сообщение. Как определено здесь в конце программы.