Академический Документы
Профессиональный Документы
Культура Документы
ОТЧЕТ
ПО ЛАБОРАТОРНОЙ РАБОТЕ № 3
по предмету
«Системный подход в разработке программного обеспечения»
Санкт-Петербург
2021.
Васильев, А. Н. Программирование на Java для начинающих
Глава 7. АБСТРАКТНЫЕ КЛАССЫ И ИНТЕРФЕЙСЫ
При описании метода в классе указывается сигнатура метода (тип
результат, название метода и список аргументов), а также тело метода с
программным кодом, выполняемым при вызове метода. Но существует
возможность ограничиться объявлением метода — указать его сигнатуру, но
не описывать тело метода. Такие методы называются абстрактными. Каждый
абстрактный метод описывается с ключевым словом abstract.
Класс, в котором есть хотя бы один абстрактный метод , также
называется абстрактным. Абстрактный класс описывается с ключевым
словом abstract. Более того, если класс просто описать с ключевым словом
abstract, то он будет абстрактным, даже если в нем нет абстрактных методов.
На основе абстрактного класса нельзя создать объект.
Интерфейс
В известном смысле интерфейс напоминает абстрактный класс, но
только в совершенно «абстрактном» и немного «урезанном» виде: интерфейс
содержит объявление методов и/или статических констант.
Интерфейсы напоминают абстрактные классы, и используются
похожим образом. Интерфейсы используются путем реализации их в классах.
Процесс реализации интерфейса в классе напоминает наследование
абстрактного суперкласса в подклассе. В случае с интерфейсами класс,
который реализует интерфейс, должен содержать описание всех методов,
объявленных в интерфейсе. Важное обстоятельство связано с тем, что один и
тот же класс может реализовать одновременно несколько интерфейсов.
Реализация интерфейса
interface name{
//описание полей и методов
}
Кроме объявления методов, в интерфейсе можно объявлять
статические константные поля. Такие поля объявляются как обычные поля со
значениями, но автоматически интерпретируются, как если бы они были
описаны с ключевыми словами static и final. Методы, объявленные в
интерфейсе, являются public-методами (хотя при объявлении методов в
интерфейсе ключевое слово public не используется).
В интерфейсе мы только объявляем методы, но не описываем их.
Интерфейс реализуется в классе. В описании класса, реализующего
интерфейс, после имени класса через ключевое слово implements указывается
имя реализуемого интерфейса.
Класс может реализовывать сразу несколько интерфейсов. Если класс
реализует несколько интерфейсов, то в описании класса после ключевого
слова implements через запятую перечисляются интерфейсы, реализуемые в
классе. В классе должны быть описаны все методы из всех реализуемых
интерфейсов.
Интерфейсные переменные
Важная особенность, связанная с использованием интерфейсов,
состоит в том, что мы можем объявить интерфейсную переменную —
переменную, «тип» которой определяется названием интерфейса. Такая
переменная может ссылаться на объект класса, реализующего данный
интерфейс.
Интерфейсная переменная может ссылаться на объект любого класса,
который реализует интерфейс.
Методы с кодом по умолчанию
Новшеством в языке Java (в версии Java 8) является возможность не только
объявлять методы в интерфейсе, но и задавать код таких методов. Проще
говоря, метод в интерфейсе можно не только объявить, но и описать. Если
метод описан в интерфейсе, то в классе, реализующем соответствующий
интерфейс, метод можно не описывать. В таком случае для метода
используется код из интерфейса. Фактически в интерфейсе для метода
задается код, используемый по умолчанию в случае, если в классе код метода
явно не определен. Методы с кодом по умолчанию описываются в
интерфейсе с ключевым словом default.
Расширение интерфейсов
Наследование применимо не только к классам, но и к интерфейсам: один
интерфейс может наследовать другой интерфейс. В результате интерфейс-
наследник «получает» описание методов (и статических констант) из
наследуемого интерфейса. Технически наследование интерфейсов (которое
называется расширением интерфейса ) реализуется так же, как и
наследование классов. В частности, в описании интерфейса-наследника
после его имени указывается ключевое слово extends , после которого
указывается имя наследуемого интерфейса.
Наследование классов и реализация интерфейсов
Класс может наследовать суперкласс и одновременно реализовывать
несколько интерфейсов.
Резюме
• Если метод в классе только объявлен, но не описан, то такой метод
называется абстрактным. Абстрактный метод описывается с ключевым
словом abstract. Класс, содержащий хотя бы один абстрактный метод,
называется абстрактным классом и описывается с ключевым словом abstract.
Если класс описан с ключевым словом abstract, то он является абстрактным,
даже если в нем нет ни одного абстрактного метода
• На основе абстрактного класса нельзя создать объект, но абстрактный класс
можно использовать при наследовании в качестве суперкласса. В подклассе,
созданном на основе абстрактного суперкласса, описываются все
абстрактные методы из абстрактного суперкласса. В противном случае (если
описаны не все абстрактные методы) подкласс также будет абстрактным.
Объектная переменная абстрактного суперкласса может ссылаться на
объекты подклассов.
• Интерфейс напоминает собой абстрактный класс. При описании интерфейса
используется ключевое слово interface. В интерфейсе объявляются методы и
статические константы (поля с постоянным значением). Интерфейсы
реализуются в классах. Если класс реализует интерфейс (или интерфейсы), то
в описании класса после имени класса указывается ключевое слово
implements, после которого указывается имя реализуемого в классе
интерфейса (если интерфейсов несколько, то их названия перечисляются
через запятую). В классе должны быть описаны (с ключевым словом public)
все методы, объявленные в интерфейсах, которые реализуются в классе — в
противном случае класс будет абстрактным.
• Интерфейс может содержать не только объявление методов, но и описание
методов (метод с кодом по умолчанию). Описание методов с кодом по
умолчанию начинается с ключевого слова default. Если метод в интерфейсе
описан с кодом по умолчанию, а в классе, который реализует такой
интерфейс, метод не описан, то для метода будет использоваться код из
интерфейса.
• Один интерфейс может наследовать другой интерфейс. В таком случае
говорят о расширении интерфейса. Интерфейс-наследник в таком случае
получает описание (и определение) методов и полей из наследуемого
интерфейса. Описывается наследование (расширение) интерфейсов так же,
как наследование классов — с использованием ключевого слова extends.
• Наследование класса и реализацию интерфейсов можно объединять:
подкласс может наследовать суперкласс и одновременно реализовывать один
или более интерфейсов. В описании подкласса после его имени через
ключевое слово extends указывается имя суперкласса и через ключевое слово
implements, через запятую перечисляются имена реализуемых в подклассе
интерфейсов.
2.3 – Java Class Design
Task 1:
As an Account is a BankAccount it would be better to use the abstract class
a) Create the AbstractBankAccount abstract class from the previous slide in
your JavaBank project
b) Update the Account class definition to extend the abstract class instead of
implementing the interface
c) Run and test your code using the TestBank class!
Task 2:
Updating the Account/AbstractBankAccount Classes
1. Move the instance fields from the Account class to the
AbstractBankAccount class
//created by timakov
public abstract class AbstractBankAccount {
public final String BANK= "JavaBank";
}
2. Move the relevant getter/setter methods from the Account class to the
AbstractBankAccount class
3. Move the withdraw method as this executes the same for both Account and
CreditAccount classes
//created by timakov
public abstract class AbstractBankAccount {
public final String BANK= "JavaBank";
return accountname;
}
return accountnum;
}
}
4. Delete the default constructor in the Account class so that you cannot create
an empty Account object
//created by timakov
public class Account extends AbstractBankAccount {
//print method
public void print() {
System.out.println(accountname + " " + accountnum + " " + balance);
}
}
5. Copy the remaining constructor from the Account class into the
AbstractBankAccount class Update the constructor name to match the class
public AbstractBankAccount(String name, int num,int amt)
{
accountname=name;
accountnum=num;
balance=amt;
}
6. Add a private instance field named bonusValue that can store an integer
value in the Account class
//created by timakov
public class Account extends AbstractBankAccount {
}
7. Create a static method named calculateInitialBonusValue that returns an int
value that carries out this calculation!
If you open an account you get a bonus value added to your opening
balance:
• Between $1 and $100 you get $10
• Between $101 and $300 you get $20
• Over $300 you get $30
private static int calculateInitialBonusValue(int amt) {
if(amt>=1&&amt<=100) return 10;
else
if(amt<=300) return 20;
else
return 30;
}
8. Update the Account constructor to call the super constructor in
AbstractBankAccount
−Use the name, num and the result of amt + calculateInitialBonusValue as
the arguments
Account(String name, int num,int amt)
{
super(name,num,(amt+calculateInitialBonusValue(amt)));
}
9. Use the calculateInitialBonusValue method to assign the initial value to the
private bonusValue field
Account(String name, int num,int amt)
{
super(name,num,(amt+calculateInitialBonusValue(amt)));
bonusValue=calculateInitialBonusValue(amt);
}
10. Updating the Account Class. If you have an Account that is not a credit
account, you will receive an additional 10% of your initial bonus value
added to each deposit over $100
public void deposit(int amt)
{
if(amt>100)
balance=balance+(amt + (int)(bonusValue * 0.1));
else
balance=balance+amt;
}
11. Updating the CreditAccount Class. Have the CreditAccount class inherit
from AbstractBankAccount instead of Account
12. For the AbstractBankAccount class this means that you have to implement a
deposit method that accepts an integer parameter and adds it to the current
value of the balance
13. Update the default constructor to accept parameters for the name, number
and initial amount for the credit account
−This allows the creation of a credit account with the default $100 credit
limit
CreditAccount(String name, int num,int amt)
{
super(name,num,amt);
this.creditLimit=100;
}
14. A constructor for a basic credit account already exists where a $100 dollar
credit limit is assigned
•JavaBank wants to implement a new scheme to make the processing of
credit accounts easier:
If you open a credit account you get a better credit limit depending on the
size of your initial deposit:
• Between $1 and $2000 you get $100
• Between $2001 and $4000 you get $200
• Over $4000 you get $300
Create a static method named calculateCreditLimit that returns an int value
that carries out this calculation!
public static int calculateCreditLimit(int amt) {
if(amt>1 && amt<=2000) return 100;
else if (amt<=4000) return 200;
else
return 300;
}
15. Update the default constructor to call calculateCreditLimit() to assign a
value for the creditLimit instance field
CreditAccount(String name, int num,int amt)
{
super(name,num,amt);
this.creditLimit=calculateCreditLimit(amt);
}
16. Update the print method in the CreditAccount class so that the output
resembles that of the Account class but also displays the credit limit
public void print() {
System.out.println("\nBank Name : " + getBankName() +
"\nAccount Holder : " + accountname +
"\nAccount Number : " + accountnum +
"\nAccount balance: " + balance +
"\nCredit Limit : " + creditLimit);
}
Testing the Abstract Class Task 1
•Quick Task: You now need to test that your changes worked with your test classes
a) Update the TestBank.java class so that the values for the a2 and a3 accounts are
provided through the constructor instead of through the setter method calls
b) Remove the setter method calls from the TestBank class!
//created by timakov
public class testBank {
public static void main(String[] args) {
// Instantiate 3 accounts
// Using constructor with values
Account A1 = new Account("Sanjay Gupta",11556,300);
// Using default constructor
Account A2 = new Account("He Xai",22338,500);
Account A3 = new Account("Ilya Mustafana",44559,1000);
// Print accounts
A1.print();
A2.print();
A3.print();
}
}
d) Run and test your code using the TestBank class!
// Instantiate 3 accounts
// Using constructor with values
Account A1 = new Account("Sanjay Gupta",11556,300);
// Using default constructor
Account A2 = new Account("He Xai",22338,1000);
Account A3 = new Account("Ilya Mustafana",44559,1000);
// Print accounts
A1.print();
A2.print();
A3.print();
C1.print();
C2.print();
}
}
// Instantiate 3 accounts
// Using constructor with values
Account A1 = new Account("Sanjay Gupta",11556,300);
// Using default constructor
Account A2 = new Account("He Xai",22338,1000);
Account A3 = new Account("Ilya Mustafana",44559,1000);
// Print accounts
System.out.println(A1.toString());
System.out.println(A2.toString());
System.out.println(A3.toString());
System.out.println(C1.toString());
System.out.println(C2.toString());
}
}
}
}
3. Add these accounts into the bankAccount array
//created by timakov
public class TestCustomerAccounts {
}
4. Create a showAllCustomerAccounts method that accepts the bankAccount array
as a parameter and uses an enhanced for loop to display all the accounts
public void showAllCustomerAccounts(AbstractBankAccount[] accounts) {
System.out.println("All customer acoounts:/n");
for(AbstractBankAccount account:accounts) {
System.out.println(account);
}
}
5. Create a showAllAccounts method that is based on the
showAllCustomerAccounts method
− Use an if statement in the enhanced for loop to include the instanceof operator to
only show accounts of type Account
− Call the method from main.
public static void showAllAccounts(AbstractBankAccount[] accounts) {
System.out.println("Account types");
for(AbstractBankAccount account:accounts) {
if(account instanceof Account) {
System.out.println(account);
}
}
}
Testing the instanceof operator Task
•Quick Task: Identify the and display the different types of bank accounts held in
the system
a) Create a showAllCreditAccounts method that is based on the showAllAccounts
method
b) Update the if statement to only show the credit accounts to the console
public static void showAllCreditAccounts(AbstractBankAccount[] accounts) {
System.out.println("All credit accounts types");
for(AbstractBankAccount account:accounts) {
if(account instanceof CreditAccount) {
System.out.println(account);
}
}
}
c) In main call the show methods so that all customer accounts, all accounts and
then all credit accounts are displayed to the console
//created by timakov
public class TestCustomerAccounts{
showAllCustomerAccounts(bankAccount);
showAllAccounts(bankAccount);
showAllCreditAccounts(bankAccount);
}
2-3: Java Class Design – Abstract Classes
Practice Activities
Vocabulary
Downward cast The type of casting that changes a generalized object to a
more specialized object type
Virtual Method The process of a call to a generalized method and actually
Invocation calls the instantiated subclass method, or appropriate subclass
method.
instanceof The operator that allows you to compare a class instance
against a class type
Casting The process of explicitly changing one data type to another
data type
Abstract class A class with an abstract constructor and at least one method
that is defined but not implemented.
Upward cast This type of casting changes a specialized object instance into
a generalized instance. It doesn't lose any of its detail but you
can't access them without downcasting the object to access
specialized methods
Abstract class A constructor without implementation that makes the class
constructor restricted in that it cannot create instances.
/**
*
*/
private static final long serialVersionUID = 1L;
// Make these variables publicly available
public String Name;
public int Accountnum;
public int Balance;
// constants
//public final static Maximum Accounts that can be created;
public final static int MaxAccounts = 10;
// constructord
public JavaBank() {
for (int i=0; i <10; i++) {
AccountNames[i] = "EMPTY";
//System.out.println(AccountNames[i]);
}
createUserInterface();
}
// set up inputDetailJPanel
inputDetailJPanel = new JPanel();
inputDetailJPanel.setBounds(16, 16, 208, 250);
inputDetailJPanel.setBorder(new TitledBorder("Input Details"));
inputDetailJPanel.setLayout(null);
contentPane.add(inputDetailJPanel);
// set up NameJLabel
NameJLabel = new JLabel();
NameJLabel.setBounds(8, 32, 90, 23);
NameJLabel.setText("Name:");
inputDetailJPanel.add(NameJLabel);
// set up NameJTextField
NameJTextField = new JTextField();
NameJTextField.setBounds(112, 32, 80, 21);
NameJTextField.setHorizontalAlignment(JTextField.RIGHT);
inputDetailJPanel.add(NameJTextField);
// set up AccountnumJLabel
AccountnumJLabel = new JLabel();
AccountnumJLabel.setBounds(8, 56, 100, 23);
AccountnumJLabel.setText("Account Number:");
inputDetailJPanel.add(AccountnumJLabel);
// set up AccountnumTextField
AccountnumJTextField = new JTextField();
AccountnumJTextField.setBounds(112, 56, 80, 21);
AccountnumJTextField.setHorizontalAlignment(JTextField.RIGHT);
inputDetailJPanel.add(AccountnumJTextField);
// set up BalanceJLabel
BalanceJLabel = new JLabel();
BalanceJLabel.setBounds(8, 80, 60, 23);
BalanceJLabel.setText("Balance:");
inputDetailJPanel.add(BalanceJLabel);
// set up BalanceTextField
BalanceJTextField = new JTextField();
BalanceJTextField.setBounds(112, 80, 80, 21);
BalanceJTextField.setHorizontalAlignment(JTextField.RIGHT);
inputDetailJPanel.add(BalanceJTextField);
// set up DepositJLabel
DepositJLabel = new JLabel();
DepositJLabel.setBounds(8, 104, 80, 23);
DepositJLabel.setText("Deposit:");
inputDetailJPanel.add(DepositJLabel);
// set up DepositJTextField
DepositJTextField = new JTextField();
DepositJTextField.setBounds(112, 104, 80, 21);
DepositJTextField.setHorizontalAlignment(JTextField.RIGHT);
inputDetailJPanel.add(DepositJTextField);
// set up WithdrawJLabel
WithdrawJLabel = new JLabel();
WithdrawJLabel.setBounds(8, 128, 60, 23);
WithdrawJLabel.setText("Withdraw:");
inputDetailJPanel.add(WithdrawJLabel);
// set up WithdrawJTextField
WithdrawJTextField = new JTextField();
WithdrawJTextField.setBounds(112, 128, 80, 21);
WithdrawJTextField.setHorizontalAlignment(JTextField.RIGHT);
inputDetailJPanel.add(WithdrawJTextField);
// set up CreateAccountButton
CreateAccountJButton = new JButton();
CreateAccountJButton.setBounds(112, 152, 80, 24);
CreateAccountJButton.setText("Create");
inputDetailJPanel.add(CreateAccountJButton);
CreateAccountJButton.addActionListener(
new ActionListener() {
// event handler called when CreateAccountJButton
// is clicked
public void actionPerformed(ActionEvent event) {
CreateAccountJButtonActionPerformed(event);
}
// set up DeleteAccountButton
DeleteAccountJButton = new JButton();
DeleteAccountJButton.setBounds(16, 152, 80, 24);
DeleteAccountJButton.setText("Delete");
inputDetailJPanel.add(DeleteAccountJButton);
DeleteAccountJButton.addActionListener(
// set up TransactionJButton
TransactionJButton = new JButton();
TransactionJButton.setBounds(16, 180, 176, 24);
TransactionJButton.setText("Make Transaction");
inputDetailJPanel.add(TransactionJButton);
TransactionJButton.addActionListener(
// set up DisplayJButton
DisplayJButton = new JButton();
DisplayJButton.setBounds(16, 208, 176, 24);
DisplayJButton.setText("Display Accounts");
inputDetailJPanel.add(DisplayJButton);
DisplayJButton.addActionListener(
// set up displayJLabel
displayJLabel = new JLabel();
displayJLabel.setBounds(240, 16, 150, 23);
displayJLabel.setText("Account Details:");
contentPane.add(displayJLabel);
// set up displayJTextArea
displayJTextArea = new JTextArea();
JScrollPane scrollPane = new JScrollPane(displayJTextArea);
scrollPane.setBounds(240,48,402,184);
scrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
contentPane.add(scrollPane);
displayJTextArea.setText("Welcome to Java Bank - There are currently no
Accounts created");
displayJTextArea.setText("");
Name = "";
//Get Accountnum from Text Field and convert to int unless blank then set to 0
if (AccountnumJTextField.getText() == "0") {
Accountnum = 0;
}
else {
Accountnum = Integer.parseInt(AccountnumJTextField.getText());
}
//Get Balance from Text Field and convert to int unless blank then set to 0
if (BalanceJTextField.getText() == "0") {
Balance = 0;
}
else {
Balance = Integer.parseInt(BalanceJTextField.getText());
}
AccountNames[noAccounts] = "USED";
//System.out.println(myAccounts[noAccounts].getaccountname());
//emptyAccount = i;
displayJTextArea.setText(myAccounts[noAccounts].getaccountname()
+ " " + myAccounts[noAccounts].getaccountnum() + " " +
myAccounts[noAccounts].getbalance());
noAccounts ++;
System.out.println(noAccounts);
}
else {
displayJTextArea.setText("Both the Name field and Account Number
must be completed");
}
if (noAccounts == 10) {
// Once account 10 is created. All accounts full.
displayJTextArea.setText("All Accounts Full!");
}
NameJTextField.setText(" ");
AccountnumJTextField.setText("0");
BalanceJTextField.setText("0");
DepositJTextField.setText("0");
WithdrawJTextField.setText("0");
displayJTextArea.setText("");
if (noAccounts == 0) {
displayJTextArea.setText("No Accounts currently created");
}else {
}
}
Name = NameJTextField.getText();
displayJTextArea.setText("");
if (noAccounts == 0) {
displayJTextArea.setText("No Accounts currently created");
}else {
for (int i=0; i<noAccounts; i++) {
displayAccountDetails(myAccounts[i]);
// displayJTextArea.append(myAccounts[i].getaccountname() + " " +
myAccounts[i].getaccountnum() + " " + myAccounts[i].getbalance() + "\n");
}
}
// clear other JTextFields for new data
NameJTextField.setText(" ");
AccountnumJTextField.setText("0");
BalanceJTextField.setText("0");
DepositJTextField.setText("0");
WithdrawJTextField.setText("0");
2. Give one reason why you might use an Abstract class rather than an Interface
Абстрактный класс позволяет создавать функциональность, которую может
использовать или изменять подкласс. Интерфейс позволяет только
определить функциональность, но не реальзовывает ее
3. Currently in your bikeproject you can instantiate an object based on the super
class Bike. Update the Bike class so that you cannot create a Bike object.
public abstract class Bike implements BikeParts
4. Remove the bike4 code from the driver class.
}
RoadBike:
public String toString()
{
return super.toString()+"This Roadbike bike has " + this.tyreWidth +
"mm tyres and a post height of " + this.postHeight + ".";
}
BikeDriver:
package bikeproject;
//created by timakov
public class BikeDriver {
System.out.println(bike1.toString());
System.out.println(bike2.toString());
System.out.println(bike3.toString());
bike1.setPostHeight("20");
// bike1.printDescription();
System.out.println(bike1.toString());
}//end method main
}//end class
a) What would the output of the following be? Explain your answer.
вывод:
“talk”-от кземплятра супер класса
“bark”-от подкласса, метод makeNose переопределен
“bark”-хоть он и создается изначально как Animal, но описывается как
Dog
b) Using the animal and dog classes above. If we added the following code to
the driver what would the output be: