Classes
🏆 Can implement classes
Given below is a tutorial you can refer to (from Oracle’s official Java tutorials) to learn how to implement java classes, in the unlikely case you don't know how to do that already.
- Classes, methods, variables – Start from the linked page and follow the next few steps in the tutorial
Class-Level Members
🏆 Can implement class-level members
You can refer to Oracle’s official Java tutorial on class-level members to learn how to implement Java class-level members, in the unlikely case you don't know how to do that already.
Associations
🏆 Can implement associations
We use instance level variables to implement associations.
A normal instance-level variable gives us a 0..1
multiplicity (also called optional associations) because a variable can hold a reference to a single object or null
.
class Logic {
Minefield minefield;
...
}
class Minefield {
...
}
A variable can be used to implement a 1
multiplicity too (also called compulsory associations).
class Logic {
ConfigGenerator cg = new ConfigGenerator();
...
}
Bi-directional associations require matching variables in both classes.
class Foo {
Bar bar;
...
}
class Bar {
Foo foo;
...
}
To implement other multiplicities, choose a suitable data structure such as Arrays, ArrayLists, HashMaps, Sets, etc.
class Minefield {
Cell[][] cell;
...
}
Draw a class diagram for the code below. Also draw an object diagram that will represent the object structure after running Main#main()
.
- Make the multiplicities as strict as possible without contradicting the code.
- You may omit the
Main
class from both diagrams.
import java.util.ArrayList;
import java.util.List;
public class Main {
public static void main(String[] args) {
Item item1 = new Item();
Item item2 = new Item();
Box box1 = new Box(item1);
Box box2 = new Box(item2);
item2.setMainCard(new Card());
item2.addPreviousBox(box1);
item2.addPreviousBox(box2);
}
}
class Box{
private Item item;
Box (Item item){
this.item = item;
}
}
class Item{
private List<Box> previousBoxes = new ArrayList<>();
private Card mainCard = null;
private Card subCard = null;
void setMainCard(Card card){
this.mainCard = card;
}
void setSubCard(Card card){
this.subCard = card;
}
void addPreviousBox(Box previousBox){
previousBoxes.add(previousBox);
}
}
class Card{
}
Suppose we wrote a program to follow the class structure given in this class diagram:
Draw object diagrams to represent the object structures after each of these steps below. Assume that we are trying to minimize the number of total objects.
i.e. apply step 1 → [diagram 1] → apply step 2 on diagarm 1 → [diagarm 2] and so on.
-
There are no persons.
-
Alfred
is the Guardian ofBruce
. -
Bruce
's contact number is the same asAlfred
's. -
Alfred
is also the guardian of another person. That person listsAlfred
s home address as his home address as well as office address. -
Alfred
has a an office address atWayne Industries
building which is different from his home address (i.e.Bat Cave
).
After step 2, the diagram should be like this:
Implement the class structure given below:
Dependencies
🏆 Can implement dependencies
Dependencies result from interactions between objects that do not result in a long-term link between the said objects.
Example:
class TaxProcessor{
double rate;
void addTax(Taxable t){
t.addTax(rate);
}
}
The code above results in this dependency.
The code does not indicate an association between the two classes because the TaxProcessor
object does not keep the Taxable
object (i.e. it’s only a short-term interaction)
Composition
🏆 Can implement composition
Composition too is implemented using a normal variable. If correctly implemented, the ‘part’ object will be deleted when the ‘whole’ object is deleted. Ideally, the ‘part’ object may not even be visible to clients of the ‘whole’ object.
Example:
class Car {
private Engine engine;
...
}
Aggregation
🏆 Can implement aggregation
Implementation is similar to that of composition except the containee object can exist even after the container object is deleted.
📦 Example:
class Car {
Person driver;
...
void drive(Person p) {
driver = p;
}
}
Association Classes
🏆 Can implement association classes
Note that while a special notation is used to indicate an association class, there is no special way to implement an association class.
Example:
At implementation level, an association class is most likely implemented as follows.
Which one of these is the suitable as an Association Class?
- a
- b
- c
- d
(a)(b)(c)(d)
Explanation: Mileage is a property of the car, and not specifically about the association between the Driver and the Car. If Mileage was defined as the total number of miles that car was driven by that driver, then it would be suitable as an association class.
Inheritance
🏆 Can implement basic inheritance
To learn how to implement inheritance in Java, you can follow [Oracle’s Java Tutorials: Inheritance]
A very beginner-friendly video about implementing Java inheritance.
Java requires all class to have a parent class. If you do not specify a parent class, Java automatically assigns the Object
class as the parent class.
Overriding
🏆 Can implement operation overriding
To override a method inherited from an ancestor class, simply re-implement the method in the target class.
📦 A simple example where the Report#print()
method is overridden by EvaluationReport#print()
method:
class Report{
void print(){
System.out.println("Printing report");
}
}
class EvaluationReport extends Report{
@Override // this annotation is optional
void print(){
System.out.println("Printing evaluation report");
}
}
class ReportMain{
public static void main(String[] args){
Report report = new Report();
report.print(); // prints "Printing report"
EvaluationReport evaluationReport = new EvaluationReport();
evaluationReport.print(); // prints "Printing evaluation report"
}
}
- Java - Overriding -- a tutorial by tutorialspoint.com
Which of these methods override another method?
- a
- b
- c
- d
- e
d
Explanation: Method overriding requires a method in a child class to use the same method name and same parameter sequence used by one of its ancestors
Overloading
🏆 Can implement overloading
An operation can be overloaded inside the same class or in sub/super classes.
📦 The constructor of the Account
class below is overloaded because there are two constructors with different signatures: ()
and (String, String, double)
. Furthermore, the save
method in the Account
class is overloaded in the child class SavingAccount
.
class Account {
Account () {
...
}
Account (String name, String number, double balance) {
...
}
void save(int amount){
...
}
}
class SavingAccount extends Account{
void save(Double amount){
...
}
}
- Method Overloading in Java a tutorial from javatpoint.com. Also mentions the topic of a related topic type promotion.
Interfaces
🏆 Can implement interfaces
Java allows multiple inheritance among interfaces. A Java class can implement multiple interfaces (and inherit from one class).
📦 The design below is allowed by Java.
Staff
interface inherits (note the solid lines) the interfacesTaxPayer
andCitizen
.TA
class implements bothStudent
interface and theStaff
interface.- Because of point 1 above,
TA
class has to implement all methods in the interfacesTaxPayer
andCitizen
. - Because of points 1,2,3, a
TA
is aStaff
, is aTaxPayer
and is aCitizen
.
Java uses the interface
keyword to declare interfaces and implements
keyword to indicate that a class implements a given interface. Inheritance among interfaces uses the extends
keyword,
just like inheritance among classes.
📦 The code for the example design given in the previous example:
interface TaxPayer {
void payTax();
}
interface Citizen {
void vote();
}
interface Staff extends Citizen, TaxPayer{
void work();
}
interface Student {
void learn();
}
class TA implements Student, Staff{
@Override
public void payTax() {
//...
}
@Override
public void vote() {
//...
}
@Override
public void work() {
//...
}
@Override
public void learn() {
//...
}
}
Abstract Classes
🏆 Can implement abstract classes
Use the abstract
keyword to identify abstract classes/methods.
📦 Partial code below gives an example of how to declare abstract classes/methods.
abstract class Account {
int number;
abstract void addInterest();
void close(){
//...
}
}
class CurrentAccount extends Account{
@Override
void addInterest() {
//...
}
}
In Java, if a class contains an abstract method, the class itself should be an abstract class i.e. if any methods of the class is 'incomplete', the class itself is 'incomplete'.
Choose the correct statements about abstract classes and
- a. A concrete class can contain an abstract method.
- b. An abstract class can contain concrete methods.
- c. An abstract class need not contain any concrete methods.
- d. An abstract class cannot be instantiated.
(b)(c)(d)
Explanation: A concrete class cannot contain even a single abstract method.
Polymorphism
🏆 Can implement polymorphism
We can use inheritance to achieve polymorphism.
📦 Continuing with the example given in [
Staff
, Admin
, and Academic
classes that achieves the desired polymorphism.
Design → Object Oriented Programming → Polymorphism →
Introduction
Polymorphism:
The ability of different objects to respond, each in its own way, to identical messages is called polymorphism. -- Object-Oriented Programming with Objective-C, Apple
Take the example of writing a payroll application for a university to facilitate payroll processing of university staff. Suppose an adjustSalary(int)
operation adjusts the salaries of all staff members. This operation
will be executed whenever the university initiates a salary adjustment for its staff. However, the adjustment formula is different for different staff categories, say admin and academic. Here is one possible way of designing the
classes in the Payroll
system.
📦 Calling adjustSalary()
method for each Staff type:
Here is the implementation of the adjustSalary(int)
operation from the above design.
class Payroll1 {
ArrayList< Admin > admins;
ArrayList< Academic > academics;
// ...
void adjustSalary(int byPercent) {
for (Admin ad: admins) {
ad.adjustSalary(byPercent);
}
for (Academic ac: academics) {
ac.adjustSalary(byPercent);
}
}
}
Note how processing is similar for the two staff types. It is as if the type of staff members is irrelevant to how they are processed inside this operation! If that is the case, can the staff type be "abstracted away" from
this method? Here is such an implementation of adjustSalary(int)
:
class Payroll2 {
ArrayList< Staff > staff;
// ...
void adjustSalary(int byPercent) {
for (Staff s: staff) {
s.adjustSalary(byPercent);
}
}
}
Notice the following:
- Only one data structure
ArrayList< Staff >
. It contains bothAdmin
andAcademic
objects but treats them asStaff
objects - Only one loop
- Outcome of the
s.adjustSalary(byPercent)
method call depends on whethers
is anAcademic
orAdmin
object
The above code is better in several ways:
- It is shorter.
- It is simpler.
- It is more flexible (this code will remain the same even if more staff types are added).
This does not mean we are getting rid of the Academic
and Admin
classes completely and replacing them with a more general class called Staff
. Rather, this part of the code “treats” both Admin
and Academic
objects as one type called Staff
.
For example, ArrayList
staff contains both Admin
and Academic
objects although it treats all of them as Staff
objects. However, when the adjustSalary(int)
operation
of these objects is called, the resulting salary adjustment will be different for Admin
objects and Academic
objects. Therefore, different types of objects are treated as a single general type, but yet
each type of object exhibits a different kind of behavior. This is called polymorphism (literally, it means “ability to take many forms”). In this example, an object that is perceived as type Staff
can be
an Admin
object or an Academic
object.
class Staff {
String name;
double salary;
void adjustSalary(int percent) {
// do nothing
}
}
//------------------------------------------
class Admin extends Staff {
@Override
void adjustSalary(int percent) {
salary = salary * percent;
}
}
//------------------------------------------
class Academic extends Staff {
@Override
void adjustSalary(int percent) {
salary = salary * percent * 2;
}
}
//------------------------------------------
class Payroll {
ArrayList< Staff > staff;
// ...
void adjustSalary(int byPercent) {
for (Staff s: staff) {
s.adjustSalary(byPercent);
}
}
}
- Oracle’s Java Tutorials: Polymorphism
- Java - Polymorphism -- a tutorial from tutorialspoint.com