Try   HackMD

Object Oriented Programming concepts

What is Object Oriented Programming

The idea of making programs using objects.

Is a paradigm of using objects to divide big projects of code.

The opposite would be the paradigm of functional programming (there are other paradigms also). Functional programming divides the code into different functions.

What is an object?

An object is a block of code that includes

  • Name (or identifier)
  • Attributes (data/variables)
  • Actions (functions/subprograms/methods)

Another definition (from the book p.291)

An object is an abstract entity that describes the data this entity has (propierties, varialbes, attributes, members) and the actions this entity can perform (methods, functions)

What is the difference between a method and an object?

Functions don't have attributes (they can have local variables or parameters but is a different concept)

Differences between attribute/parameter/local variable

When we instanciate an object (create a vehicle or a goomba) we usually are going to initialize the variables (attributes) that are inside the object that will be in memory for the life of the object.

When we have a local variable the life of that variable is only the local block (usually a methhod) where is executed. We don't have access to it afterwards.

Parameters are variables that are inputed into methods (they are from outside that method)

Why using OOP?

OOP is not perfect but what it aims is to create modularity

Modularity

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

modulor by Le Corbusier

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

Lego Bricks

Modularity is the concept of dividing the code (the program) into modules so each of the modules can be re-used in other projects and also can be worked on parallel.

This doesn't mean that the code itself is more efficient in doing its job! It means that can be more efficient to divide the task into teams or reuse code.

This is done using not only OOP but also the concept of encapsulation

Encapsulation

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

One way to achieve the best modularity is by restricting the access to methods or variables that are in objects so only the objects themselves are in charge of changing those values or interact with them.

Encapsulation is the act of restrict the access to the variables or methods of an object to the rest of the code in order to have more control over its access.

Why restrict?

The idea of restricting the access to the data of the object is to make the object itself responsible to change those values and validate them.

This makes it easier to find "who to blame" of doing or not doing something in the code. For example the object "Client" maybe should be responsible for checking if the email of the client corresponds to the structure of an email

This is an example:

https://www.baeldung.com/java-email-validation-regex

public void testUsingSimpleRegex() { emailAddress = "username@domain.com"; regexPattern = "^(.+)@(\\S+)$"; assertTrue(EmailValidation.patternMatches(emailAddress, regexPattern)); }

Note: you're not supposed to know regular expressions (regex) for this course!

So the idea is that the program will be easier to debug.

Access modifiers

More on this here:

https://www.baeldung.com/java-access-modifiers

https://www.geeksforgeeks.org/access-modifiers-java/

We are going to work mainly with 2

  • private: Only the class itself can access to it
  • public: Every part of the code can access to it.

Here you have more information:

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

This modifier should be before each class/attribute/method

Instanciation

(page 292)

The concept of instanciation is how we have "blueprints" and "instances".

Each of the instances has or may have different attributes.

For example if we're drawing we can have diffent circles, each of them with one radius and one center point.

So for creating these instances we need to, ehem, instanciate them as a variable with the object type. In this case for example

Circle circle1 = new Circle();

What does this mean?

Circle is the Object type that we have access to (Circle.java)
Circle1 is the identifier of that object
new is the keyword to call constructors
Circle() is a special method of the class Circle called constructor that is going to be executed when we create this instance.

Example for explaining instances (car)

We may have the object Vehicle that has the attributes such as color, model, year and so on and then the different instances that will be specific vehicles that are a Volvo, a Mercedes, a Dacia or a Toyota

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

generic car that doesn't have a particular color or specifics

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

three instances of Car that have particular specifics from the idea of car

Example for explaining instances (circle)

If we have a program that creates circles we may use the object "Circle"

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

inkscape tool of creating circle

But then we might have different circles done in that program (for example here in processing)

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

https://www.youtube.com/watch?v=uopj9qLI4m0
Each of those circles are instances of the object Circle.

What is a constructor method

A constructor method is a method inside an object that has the same name of the object (even with caps) and is going to be executed every time that that object is instanciated.

Is always void implicitly (indirectly) and it can have parameters.

We can have more than one constructor defined in one class using method overloading (concept for later)

Example:

Data that is static and dynamic

This is a very important concept that they ask almost every year in the exam. Is usually confused with final (that is constant)

A static method or static variable is a variable that is defined in the blueprint (in the class) of the object and it is shared by all the instances. There is no need to instanciate an object to access a public static method/attribute.

Example:

We have Circles

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

Circles can have a static attribute named "numberOfCircles" that is updated each time that we create (o destroy) a circle that just count how many instances we have in our program.

This variable is going to change over time (when we instanciate all the circles) but is shared by all the circles.

We can even call it if we didn't instanciate any circle in our program. Its value should be 0 (if everything works as intended).

In the same case we can have PI as a constant to calculate the area of those circles inside the object Circle. In this case we also don't need to have it 30 times if we have 30 circles and also we're not going to change it. So it will be final static double PI = 3.1415...;

In the case of methods this is usually for methods that are independent from the instanciation. We can access them calling the class (with capital letter) and then the method.

For example:

System.out.println();

Also very common in Math

Math.random();

The typical object in Java

The typical object in java is this template (Also can be called POJO, Plain Old Java Object)

public class MyObject { //MyObject goes with PascalCase private int variable1; //names with camelCase private boolean adjetive1; private String variable2; //all variables private by default //only use static or final if we need to. public MyObject() { this.variable1 = 2; //default value this.adjetive1 = true; //default value this.variable2 = "default"; //default value } //constructor with no parameters and set default value public MyObject(int x, boolean y, String z) { this.variable1 = x; //input value this.adjetive1 = y; //input value this.variable2 = z; //input value } // getters and setters methods // accessor and mutators methods // accessors public int getVariable1() { return this.variable1; } public boolean isAdjective1(){ return this.adjetive1; } public String getVariable2() { return this.variable2; } // mutators public void setVariable1(int x) { this.variable1 = x; } public void setAdjetive1(boolean newAdjective1) { this.adjetive1 = newAdjective1; } public void setVariable2(String x) { this.variable2 = x; } }

There are other methods that are a little bit more interesting but depend on the context and they may not be held into what is a POJO.

Some of them are

toString

equalsTo

compare

When we don't want to have an accessor or mutator

For example if we have one of our variables that is an array (or a list). If we allow access to that list or array that array can be changed without control, if we just create access to a specific element (given the index or the value) we have more control over the array.

Also we may restrict the methods that change names if this program is not going to actually change the name (or the ID) of some object/person.

Instance methods (or dynamic methods)

The instance methods are those that depend on the specific instance that we are working on. If we have a car that has a drive (or accelerate or brake) is going to be depending on the specifics of one of the instances of the car simulation.

If we have move() in Circle is going to probably change the specific attributes of the circle that has been called.

Example with Circle

public class Circle { double radius; String color; double centerX; double centerY; Circle() { // the implementation of the contructor } //accessor public double getRadius() { return this.radius;} public String getColor() { return this.color;} public double getArea() {return this.radius*this.radius*Math.PI;} public double getCenterX() { return this.centerX; } public double getCenterY() { return this.centerY; } //mutators public void setRadius(double radius) { this.radius = radius; } public void setColor(String color) { this.color = color; } // "other" public void move(double deltaX, double deltaY) { this.centerX = this.centerX + deltaX; this.centerY = this.centerY + deltaY; } }

Comments on this:

We have some variables and some accessors and mutators. Take note that we don't have a mutator method for centerX or centerY because for that we're using "move"

Also there is no mutator for Area because if you want to change the area of the circle you need to change the radius.

Create instances

https://www3.ntu.edu.sg/home/ehchua/programming/java/J3a_OOPBasics.html
(2.4)

To create an instance we need to do it in other part of the code. Usually we have in OOP 2 classes. The "main" class where we have the public static void main(String[] args) method and the class that we want to instanciate (that we want to play with)

In the one that we have the main method we need to call the other in this way:

  • Declare an instance identifier (instance name) of a particular class.
  • Construct the instance (i.e., allocate storage for the instance and initialize the instance) using the "new" operator.

For examples, suppose that we have a class called Circle, we can create instances of Circle as follows:

// Declare 3 instances of the class Circle, c1, c2, and c3
Circle c1, c2, c3;  // They hold a special value called null
// Construct the instances via new operator
c1 = new Circle();
c2 = new Circle(2.0);
c3 = new Circle(3.0, "red");
 
// You can Declare and Construct in the same statement
Circle c4 = new Circle();

This is why is common to write something like

Potato potato = new Potato();

In this sentence the first Potato is the declaration of the type of the variable (the class Potato), then the name of that instance (that could be potato or patata o pomme de terre or картофел) and last the construction of the instance using the new statement.

Remember that constructors can have (or not) several parameters depending on the context. For example if we have a parking lot and we want to model the traffic incoming one of the elements that we do want to know to make an instance of a vehicle is its plate.

British_car_registration_plate_labels-UK.svg

So we can make a constructor that asks for it and create an instance of Vehicle with its plate.

So if they ask you "write the code to instanciate a vehicle with the plate 2312351X"

you have to answer

Vehicle v = new Vehicle("2312351X");

In this case it would be also valid if we change the name of the variable to something else:

Vehicle potato = new Vehicle("2312351X");

Exercise (simple)

Use the example class Circle to create some instances

Circle class in the spoiler

/**
 * The Circle class models a circle with a radius and color.
 */
public class Circle {  // Save as "Circle.java"
   // private instance variable, not accessible from outside this class
   private double radius;
   private String color;
   
   // Constructors (overloaded)
   /** Constructs a Circle instance with default value for radius and color */
   public Circle() {  // 1st (default) constructor
      radius = 1.0;
      color = "red";
   }
   
   /** Constructs a Circle instance with the given radius and default color */
   public Circle(double r) {  // 2nd constructor
      radius = r;
      color = "red";
   }
    
   public Circle (double r, String c){
       radius = r;
       color = c;
   }
   
   /** Returns the radius */
   public double getRadius() {
     return radius; 
   }
   
   /** Returns the area of this Circle instance */
   public double getArea() {
      return radius*radius*Math.PI;
   }
}

Create 5 instances.

  • The first called circle1 should be a circle with the default parameters
  • The second called c2 should be a circle with radius 5
  • The third called c3 should be a circle with radius 10 and colour "green"
  • The forth called colinRobinson should be a circle with radius -2 and color "greenish"
  • The fifth called circle5 is a circle with the default radius but the color "blue"

Answer in the spoiler:

   Circle circle1 = new Circle();
   Circle c2 = new Circle(5.0);
   Circle c3 = new Circle(10.0, "green");
   Circle colinRobinson = new Circle(-2.0, "greenish");
   Circle circle5 = new Circle(1.0, "blue");

Comments:

This class doesn't have implemented any kind of validation so we can have this types of negative radius (see colinRobinson)

In the last one we don't have access to a constructor that has only a default radius and choose the color so we have to either hardcode the default radius or use a default circle and change the attribute of the colour.

Exercise of creating and implementing a class

In this exercise we're going to model something simple like a Book and we're going to implement the accessors and mutators.

The variables that we are going to set depend on the context. It's not the same a library that a bookstore or a physics simulation. In a bookstore the price is relevant, in a library (personal or communal) you might find interesting how many times has been lended that specific book. In a physics modelling system, we need to know the specifics of the size and the material of the book.

In this "generic" case we're going to use some of this data. You need to understand which types of primitive variables do we need. Later we might have other objects as variables.

So, exercise: implement the variables that we need to have a title, author number of pages, ISBN (International Serial Book Number) and if is written in Korean.

Sin título
(source and explanation in Spanish about ISBN https://kitzalet.com/editorial-digital/que-es-el-isbn-de-un-libro/)

Solution in the spoiler

public class Book {
   private String title; 
   private String author;
    private int pages; //can be also called numberOfPages
    private String ISBN; //this could be also a double maybe but better be saved in a string because is a long number
    private boolean inKorean;
}

Here we have the attributes but we're missing the actions. For this we need a couple of constructors and also the accessors and mutators (getters and setters)

Let's **code a constructor method that has some default values, another that has one parameter, and other that has 2 parameters. **

Solution in the spoiler (with the rest of the class)

public class Book {
   private String title; 
   private String author;
    private int pages; //can be also called numberOfPages
    private String ISBN; //this could be also a double maybe but better be saved in a string because is a long number
    private boolean inKorean;
    
    public Book() {
        this.title = "untitled";
        this.author = "anonimous";
        this.pages = 0;
        this.ISBN = "none";
        this.inKorean = false;
    }
    
    public Book (String title) {
        this.title = title;
        this.author = "anonimous";
        this.pages = 0;
        this.ISBN = "none";
        this.inKorean = false;     
    }
    
    public Book (String title, int numberOfPages) {
        this.title = title;
        this.author = "anonimous";
        this.pages = numberOfPages;
        this.ISBN = "none";
        this.inKorean = false;     
    }
}

We can add also a constructor that accepts all the parameters (title, author, pages, ISBN and if it's in Korean). Implement a constructor that accespts all 5 attributes as parameters.

Solution in the spoiler. In this case we don't have to write all the class for do the solution (great because the exam is short)

public Book (String title, String author, int numberOfPages, String ISBN, boolean inKorean) {
       this.title=title;
       this.author=author;
       this.pages=numberOfPages;
       this.ISBN=ISBN;
       this.inKorean=inKorean;
}

Now that we have covered all the constructors (you could be asked to do a Constructor with 3 or 4 parameters also) we can move on on the next thing:

Implement the accessors and the mutators for Book

Solution on the spoiler:

Accessors:

public String getTitle() { return this.title; } public String getAuthor() { return this.author; } public int getPages() { return this.pages; } public String getISBN() { return this; } public boolean isInKorean() { //here instead of getInKorean we use //isInKorean because makes more sense when reading return this.inKorean; }

Mutators:

public void setTitle(String title) { this.title = title; } public void setAuthor(String author) { this.author = author; } public void setPages(int pages) { this.pages = pages; } public void setISBN(String ISBN) { this.ISBN = ISBN; } public void setInKorean(boolean inKorean) { this.inKorean = inKorean; }

The dot operator

The dot operator allows us to acces to methods (actions) or members (also called attributes or variables) that we have access to. To do that we use the dot operator.

For example using the Circle class we can instanciate one circle and then get access to getArea to get the Area of the circle

Circle c1 = new Circle();
double area = c1.getArea();

Rules

We can access to things that we have access to. If a variable is private we cannot access to it unless we are writing in that class (And we usually call it from other class).

For example if we're using myObject from before in an instance we cannot access the attributes directly

MyObject instance = new MyObject();
int x = instance.variable1; //this raises an error in compiling time because you don't have access to the variable directly

That's why we usually have accessor methods so we would write something like this

MyObject instance = new MyObject();
int x = instance.getVariable1();

This is why we usually change the name of the accessors for booleans so they are easier to see what's happening

For example with the previous book

Book book1 = new Book();
if (book1.isInKorean()) {
    Translator.translateFromKorean(book1);
}

In this case we are going to translate from Korean if the book is in Korean.

UML diagrams

To summarize the concepts that we have inside a class without writting all them down we use a UML (Unified Modelling Language) diagrams.

They are several types depending on the level of detail. Like maps they can be just an overview or get in a lot of detail.

If we want to do the UML diagram of one object we make a box and divide it into the three elements that an object has.

Object name
Object attributes
Object actions

I suggest use diagrams.net to do these kind of stuff or just writting them down.

Here we have the example of the UML diagram of the sample class "MyObject"

imagen

How do we write them? Using this scheme:

features
(source: https://icarus.cs.weber.edu/~dab/cs1410/textbook/9.Classes_And_Objects/uml.html)

There are different flavours of UML diagrams. For example, using the book notation this would be the UML diagram of MyObject

imagen

Both options are fine but choose your fighter

Sin título

and be consistent with it

Example of the class Dog UML diagram.

imagen
Credit: M.Z

Exercise:

Do the UML diagram of Book.

Different contexts in modelling

This is not something that the exam asks directly but I think that gives a lot of context and understanding to the student about why do we have these variables and not others.

When we create programs we model reality. This sounds like The Matrix or something from science fiction but it's true. The difference from the program to enroll students into a school and The Matrix is that the former only cares about some information of the student.

800px-The.Matrix.glmatrix.1
the Matrix modeling the whole reality

Depending on the context, in our modelling we're going to model only relevant information for our system. If we want to enroll people in our school, for example, we don't need to know how much do they weight.

Example with Book

There is an example with book and the information about it was given. In this case we're going to dive a little bit in different context that they will have for modelling a book.

In a bookstore we care about the price of the book and if it's in promotion. In a library, however we care if it's lended or not and probably we're going to store in each book a lending history so we know how many times was lended, to who and how long.

If we're publishers (editors) we might need to know what is the printCost and probably we can set if the book is actually published of it's not yet published.

In a videogame (Such as Skyrim, minecraft of book of hours) a book will need more information becuse the book usually has an actual place in the virtual world that the program need to know.

The result of these would be something like this

In a library

Book
String: title
String: author
String: ISBN
String: genre
boolean: lended
Lending[]: lendingHistory
Library: location

In a bookshop

Book
String: title
String: author
String: ISBN
String: genre
double: price
boolean: promotion
String: section //section of the bookstore

In minecraft

Book
Point: position //Point is a class to store a position X,Y,Z and posibly the rotation
String: title
String: content
MinecraftUser: author
int: pages

Example with Car

In an authorized dealer (car shop)

Car
double: price
boolean: promotion
String: brand
boolean: secondHand
String[]: extras
String: category
int: consumption
int: power
String: colour

In a car workshop

Car
String: plate //registration plate
Client: owner
String: problems
String: brand
String: model
String: dateOfArrival

In a videogame (such as GTA 5)

Car
String: plate
String: model
Point: place
int: spawnRate
long: value
int: healthPoints

Exercise about the Car

Write some variables that would make sense to the Car object in the context of a program of a Parking Area

Exercise:

Think of a object (Suitcase, person, student) and at least three different contexts (programs that need info from the Suitcases, people, students) and create these schemes about the different variables that these objects should have and what are the types of those variables (remember that java is a highly typed programming language)

Dependencies

More info:
https://www.geeksforgeeks.org/association-composition-aggregation-java/

In OOP different objects have different relationships between each other thes are the studs, the "boops" in the lego and how they interact.

There are three (main) ways to 2 objects to interact

  • Association (A uses B)
  • Aggregation (A has a B)
  • Inheritance (A is a B)

There is no consensus between the difference between dependency and association. In some sources I've found that the association is a type of dependency and in others dependency is a type of association.

Association

Also called dependency

Association in dependency is that the class A uses B, usually a (public) method from B. It's the lightest way of communication between classes. It's represented by a dashed arrow

imagen

This is common for example when we have a static library like "Math"

Also in representing UML diagrams we put in top of the line "uses" because this is "usage" of one class to the other

imagen

Dependency as the other associations is directional. That means that if ClassA uses ClassB doesn't mean that necessarely ClassB uses classA. ClassB can be independent from classA

Aggregation

In aggregation we are a step foward between the 2 classes and one of them is part of the attributes of the other. When this happen we have Objects as attributes (members)

imagen

Aggregation, as dependecy

Example with IMDB

A typical example when modeling Databases (DB) is when we have an object that refers to another. For example in IMDB if we have a title (that refers to a movie title usually) it has references to complex objects of people (names in the IMBD context) for each of the crew that has done the movie.

If we go to the movie Dune for example

https://www.imdb.com/title/tt1160419/

imagen

We can see that the crew doesn't only show their names but also their photos, and, if we click on them we can see more information on that person (in this case Oscar Isaac)

https://www.imdb.com/name/nm1209966

imagen

Here "title" doesn't only store the title of a movie but all the information that you can see in the webpage.

imagen

Inheritance

Also called in java "extension" because we use "class A extends B"

Multiplicities

When we have objects that aggregate between each other we can have different numbers of "how many objects in A has a B" the short table is this:

Common multiplicities

Number Meaning
1 Exactly one
01 Zero or one
* many
0* zero to many
1 * 1 to many

Example of 1 in Spanish ID (DNI). In this case a person can only have one DNI (ID) and an ID can only have one owner.

imagen

What could be the context of this example?

Example of 01 is passport in Spain since passports in Spain are optional.

imagen

Also in this example the multiplicities are also directional, one person may not have a passport but all the passports have owners.

Example of many (*) can be the products of a store.

imagen

In this case Store has Products but Product in this context doesn't have a Store (maybe because is implicit, depends on the design).

Example of 0 to many is almost all the elements that can be empty or have a lot of information for example when we have a library that can be empty or have a lot of Books.

imagen

An example of 1 to many is a store that saves the customer information including addresses to send to the customers. One costumer needs to have one address when they register but they can add more if they please.

imagen

Reference for multiplicities
https://www.umlboard.com/docs/relations/multiplicity/

Possible extra work

  • Finding out the working of methods like toString(), compare, equals
  • Implement the class Triangle with different constructors template here:

public class Triangle {
int p1x;
int p1y;
int p2x;
int p2y;
int p3x;
int p3y;

public Triangle(int p1x, int p1y, int p2x, int p2y, int p3x, int p3y) {
//code missing

}

public Triangle(int p1x, int p1y, double alpha, int side1, double beta, int side2) {
//code missing

}

public Triangle(int side1, int side2, int side3) {
//code missing
//in this case it will assume default values for the p1x and p1y, probably 0,0

}

}

  • Presentation about regular expressions and how to (briefly, try to understand it).

Use case of a UML

In the exams they usually ask for a (or even 2) UML diagrams. There are 2 types of UML diagrams asked in the exam

  1. The ones that only describe one class in detail. These need to have the 3 boxes with name, members(attributes) and methods with their + for public and - for private
  2. The ones that only describes the relationships between classes. In these cases you need to understand what are the relationship between the classes and draw accordingly. I suggest to remember the 3 different arrows AND write also "uses" "has a" or "is a" to be super clear for the person who marks. Here an example of those

imagen

Reference that I need to check

https://nirajrules.wordpress.com/2011/07/15/association-vs-dependency-vs-aggregation-vs-composition/

Example of coding with filling an array

We have a department of an university that has a small library with book related to Necromancy, Alchemy or other Hidden Arts. We're using a model where each department has their own array of books. In this first iteration we're asuming that they only have one of each.

public class Department
{
    private String name;
    private Book[] library;
    
    //constructor, getters and setters (not setter and getter for library)
}

Here we have a simplified version of the class Book

public class Book
{
    private String title;
    private String isbn;
    
    //constructor, getters and setters
}

addBook(Book b)

Statement:

In this case we're going to implement the method addBook(Book b) that will add a book in the first empty position of the array library and return the position (ie the index of the array) at which the book has been added. If it's not possible to fit the book into the library, then it should return -1.

Working

To do that first we need to work on the signature of the method. This is to have clear
a) the access of the method. By default the methods are public unless stated otherwise.
b) the return type (or if there is not): int (since is the index of an array or -1)
c) the name of the method: addBook
d) the parameters (if any) of the method: Book b

Remember that java is a highly typed programming language so even Book b are 2 words, it refers to only one parameter that is called "b" and the type of the parameter is Book.

With that we can construct or method, the first line

First with the access modifier public, then the return type int, then the name of the method addBook and in the parenthesis the parameters (if any), in this case Book b

Altogether combined like a megazord looks like this

    public int addBook(Book b)

Now we can work inside the method. For that, usually we need to know where is this method written to know which things does it have access to.

In this case the hint is that we're working with the array library that we know that is held in the object Department.

Once we know we need to loop throug the array.

How to loop through an array in java

To loop trough an array in java is with a for loop.

    int[] numbers = {2,3,6,4,558,14,2}; //sample array of ints 
    for (int i =0; i < numbers.length; i ++){
        //do something with numbers[i] to have each element
    }

So in this case need to add this loop it would look like this

    public int addBook(Book b) {
        for (int i = 0; i < library.length ;i ++) {
            
            
        }      
    }

The next step is finding when we don't have a book in the library. For that we need to know the context of null pointer.

The null is a special value that is "the pointer that doesn't point anywhere" and refers usually to empty spaces in an array or a list or something that is not instanciated yet.

So if we want to know the first index on the array that is free we need to know the first element which value is null

null and 0 are not the same thing!

To access the element of the library we need to write library[i]

    public int addBook(Book b) {
        for (int i = 0; i < library.length ;i ++) {
            if (library[i] == null) {
                
            }            
        }      
    }

We're not using here any getters to get the information because we're in that class so we don't need them! (so no getLibrary nor anything like that)

    public int addBook(Book b) {
        for (int i = 0; i < library.length ;i ++) {
            if (library[i] == null) {
                
            }            
        }      
    }

Now we need to add the book and return the position of that book

To add the book we just update the variable with library[i]=b;

And return the index is returning the variable i. This will terminate the method.

    public int addBook(Book b) {
        for (int i = 0; i < library.length ;i ++) {
            if (library[i] == null) {
                library[i]=b;
                return i;
            }            
        }      
    }

To finish we need to do the option where the array (the library) is full.

In this case we don't need a flag variable because if we find an empty spot we're going to fill it. So if the for loop ends, it means that there is no space.

So the return -1 would need to happen after the for loop

Result

    public int addBook(Book b) {
        for (int i = 0; i < library.length ;i ++) {
            if (library[i] == null) {
                library[i]=b;
                return i;
            }            
        }   
        return -1;
    }

findBookByISBN

Statement:

In this case we're going to implement the method findBookByISBN(String isbn) that will find a book in array of the library of the deparment. If it finds something that has the ISBN is going to retrieve the object. If there is no fit, it's going to return null.

Working:

Finding signature of the method (in order)

A) access modifier: public (by default)
B) return type: Book (it returns the pointer of a Book, null can be also a special value for a Book)
C) name of the method: findBookByISBN (given)
D) parameters and types of them if any: 1 parameter: String ISBN

Alltogeher comes as:

    public Book findBookByISBN(String isbn)

Now we have to iterate through the array so let's do the for loop

    public Book findBookByISBN(String isbn){
        for (int i = 0; i < library.length ;i ++) {
            
            
        }      
    }

In this case we need to check if the book itself has the correct ISBN to acces to that ISBN we need to use the getter from that specific book.

To access the specific book in the array (the ith element) we use library[i], for accessing a method of the instance of that book we use the dot operator and we write library[i].getISBN() that is going to return the string of the ISBN.

So the condition would be if(library[i].getISBN() == isbn) since the isbn that we have as an input is called just isbn (is the isbn in public Book findBookByISBN(String isbn))

so we have something like this:

    public Book findBookByISBN(String isbn){
        for (int i = 0; i < library.length ;i ++) {
            if(library[i].getISBN() == isbn) {
                
            }            
        }      
    }

The proper way though is using the equals method

    public Book findBookByISBN(String isbn){
        for (int i = 0; i < library.length ;i ++) {
            if(library[i].getISBN().equals(isbn)) {
                
            }            
        }      
    }

Also this one would work since the equals method has to be commutative.

    public Book findBookByISBN(String isbn){
        for (int i = 0; i < library.length ;i ++) {
            if(isbn.equals(library[i].getISBN())) {
                
            }            
        }      
    }

The equals method

more info here: https://hackmd.io/zfx3YkE9QD6-lnNz42kkbQ?view#Consecuences-of-referencing-and-objects-When-are-2-objects-equal

inhale

equals() method:

In java objects (including strings) are usually reference (actually they are called reference variables) to other elements and in the case of strings they can be generated as a 'value' (String a = "potato") or as a reference(pointer) to a value (String b = new String("potato")). If we compare values with the reference we're not going to have the expected result even if want to.

So for "good practice" in java we usually work with the method equals for anything that is an object and not a primitive.

Sometimes part of the marks is by using this method properly

More info here:

https://www.geeksforgeeks.org/difference-between-and-equals-method-in-java/

How to use it?

access the variable and then with the dot operator call the method equals and send as a parameter the object that you want to compare with.

 String a = "potato";
 a.equals("tomato"); //false
 String b = new String ("tabacco");
 b.equals(a); //also false

Here the full program from geeks for geeks with the options of comparasion

// Java program to understand 
// the concept of == operator

public class Test {
	public static void main(String[] args)
	{
		String s1 = "HELLO";
		String s2 = "HELLO";
		String s3 = new String("HELLO");

		System.out.println(s1 == s2); // true
		System.out.println(s1 == s3); // false
		System.out.println(s1.equals(s2)); // true
		System.out.println(s1.equals(s3)); // true
	}
}
//source https://www.geeksforgeeks.org/difference-between-and-equals-method-in-java/

TL; DR:

If it's not a primitive, better compare using equals() method

Back to the show. We're with this:

    public Book findBookByISBN(String isbn){
        for (int i = 0; i < library.length ;i ++) {
            if(library[i].getISBN().equals(isbn)) {
                
            }            
        }      
    }

Now the statement told us that we have to return the reference of that book and else we return null. So let's add those 2 returns. First the return in the case that we find the book with that ISBN:

    public Book findBookByISBN(String isbn){
        for (int i = 0; i < library.length ;i ++) {
            if(library[i].getISBN().equals(isbn)) {
                return library[i];
            }            
        }      
    }

Since return statement is going to terminate the method, we can write the other return just after the for loop because that means that we haven't found the book with that ISBN. We only have to write return null

Result

    public Book findBookByISBN(String isbn){
        for (int i = 0; i < library.length ;i ++) {
            if(library[i].getISBN().equals(isbn)) {
                return library[i];
            }            
        }
        return null;
    }

Exercise: findBookByTitle

Do the same thing but finding the book by title. We're assuming that titles don't repeat themselves.

Statement

Construct the method findBookByTitle (String title) that will return the reference of the first book that is in the library that has the same title. It will return null if there was no book with that title.

Solution in the spoiler

imagen
credit J.A

Exercise: findAuthorInLibrary

In this case we're going to implement the method findAuthorInLibrary that will find a book in array of the library of the deparment with the author as a parameter. If it finds something that has the author is going to return true, if not it's going to return false.

public boolean findAuthorInLibrary (String author){
    for (int i = 0; i < library.length ;i ++) {
        if (library[i].getAuthor().equals(author))){
            return true;
        }
    }
    return false;
}


Exercise: findStartingAuthor

The IB likes to do this kind of thing of introduce a method, how it works and then make the student use the method described. This is one example of this.

In this case we're going to get introduced to a method that you will need to use in the final method.

In this case startsWith(string test) is a method that will return true if the string starts with that test string and false otherwise.

String myStr = "Hello";
System.out.println(myStr.startsWith("Hel"));   // true
System.out.println(myStr.startsWith("llo"));   // false
System.out.println(myStr.startsWith("o"));     // false

reference: https://www.w3schools.com/java/ref_string_startswith.asp

findStartingAuthor is a method that is going to return if there is at least one book with the name or the start of the name that you wrote as a parameter.

You should use the method startsWith in your solution.

Remember that you don't need to implement the method startsWith, you only need to use it

Soolution after the spoilers

public boolean StartsWithAuthor(String au){ for (int=0; int < library.length; i++){ if (library[i].getAuthor().startsWith(au)){ return true; } } return false; }

credit K.B.

Another context. The retailers

A company that sells cars is using an OOP approach creating a program to manage its administration.

We have the class SalesPerson

class SalesPerson // each object contains details of one salesperson
{
private String name;
private String id;
private Sales[] salesHistory; // details of the different sales
private int count = 0; // number of sales made
//constructor for a new salesperson
public SalesPerson(String id)
{
// code missing
}
// constructor for a salesperson transferred (together with
// their sales details) from another branch
public SalesPerson(String id, Sales[] s, int c)
{
// code missing
}
public int getCount(){return count;}
public String getId() {return id;}
public void setSalesHistory(Sales s)
{
salesHistory[count] = s;
count = count +1;
}
public double calcTotalSales() // calculates total sales for the
// salesperson
{

}
public Sales largestSale() // calculates the sale with the largest
// value
{
// code missing
}
    

}

Then we have the object Sale

public class Sale {
    private int productCode;
    private double quantity;
    private double price;
    //constructor, accessors and mutators not shown
}

Find the largest x in an array

Statement

Construct the code that implements the method largestSale, a method that returns the Sale objects that was the largest sale. To be the biggest sale has to be the more amount of money transfered.

Process

We have covered already in arrays how to find a maximum. The idea is
a) set the first as the maximum
b) iterate through the array with a loop
c) in that loop check if the conditions to change the maximum changes
d) in that case, update the maximum and/or the maximum index (this depends on context)
e) after the loop act accordingly to the context (output, return, etc)

First remember that we need to know the context of the method. Where it's written. Look into the statement and the context. This is important to know what other elements do we have access to.

In this case the method largestSale is in the object SalesPerson.

The next thing is to know where do we have to iterate through. In this case we have to iterate through an array of sales, then name of that array is salesHistory. A variable that is in SalesPerson.

With this information we can start writing. First the method itself

//written in SalesPerson
public Sales largestSale() {
    
    
}

The step a is to define the maximum as the first element. The array has a first element that we can access trough 0

//written in SalesPerson
public Sales largestSale() {
    Sale maxSale = salesHistory[0];
    int maxSaleIndex = 0;
    
}

Do we need to also store the index? Depending on the context. If you only need the value, we don't need the index. But if you need either the order or the object itself we actually need it because is what we want to return.

The next step is to make the iteration through the array. From what I saw they are 2 types of arrays in IB exams. The arrays that have a counter and the arrays that don't have a counter.

To know it we need to look into the context. The name of the variable should be to count how many elements do we have. Remember that the name can be "counter" or can be "totalSales" or something different but they have the same purpose.

//written in SalesPerson
public Sales largestSale() {
    Sale maxSale = salesHistory[0];
    int maxSaleIndex = 0;
    for(int i=0; i<counter; i++){
        
    }
}

If we did't have a counter, the loop would look like this using length.

//written in SalesPerson
public Sales largestSale() {
    Sale maxSale = salesHistory[0];
    int maxSaleIndex = 0;
    for(int i=0; i<salesHistory.length; i++){
        
    }
}

The next step is to calculate how much is the sale. So we need to do calculations with the elements that are inside Sale. How do we do it? We need to find this information in the object Sales. The members (the data) that we have is productCode, quantity and price. To calculate the sale we need to multiply quantity and price.

We use double here because quantity and price are doubles already.

//written in SalesPerson
public Sales largestSale() {
    Sale maxSale = salesHistory[0];
    int maxSaleIndex = 0;
    for(int i=0; i<counter; i++){
        double currentSaleTotal = salesHistory[i].getQuantity() * salesHistory[i].getPrice();

    }
}

Now we compare the currentSaleTotal with the maxSale total in an if. If the current is bigger, it will mean that we need to change the maximum.

//written in SalesPerson
public Sales largestSale() {
    Sale maxSale = salesHistory[0];
    int maxSaleIndex = 0;
    for(int i=0; i<counter; i++){
        double currentSaleTotal = salesHistory[i].getQuantity() * salesHistory[i].getPrice();
        if (currentSaleTotal > maxSale.getQuantity() *maxSale.getPrice()) {
            maxSale = salesHistory[i];
            maxSaleIndex = i;
        }
    }
}

Then after the loop we have to return (because the statment says so) the Sale that was the biggest.

//written in SalesPerson
public Sales largestSale() {
    Sale maxSale = salesHistory[0];
    int maxSaleIndex = 0;
    for(int i=0; i<counter; i++){
        double currentSaleTotal = salesHistory[i].getQuantity() * salesHistory[i].getPrice();
        if (currentSaleTotal > maxSale.getQuantity() *maxSale.getPrice()) {
            maxSale = salesHistory[i];
            maxSaleIndex = i;
        }
    }
    return maxSale;
}

In this case we don't need the maxSaleIndex AND the max sale. This one works also.

//written in SalesPerson
public Sales largestSale() {
    Sale maxSale = salesHistory[0];
    for(int i=0; i<counter; i++){
        double currentSaleTotal = salesHistory[i].getQuantity() * salesHistory[i].getPrice();
        if (currentSaleTotal > maxSale.getQuantity() *maxSale.getPrice()) {
            maxSale = salesHistory[i];
        }
    }
    return maxSale;
}

Another version

//written in SalesPerson
public Sales largestSale() {
    Sale maxSaleI = 0;
    for(int i=1; i<counter; i++){
        double currentSaleTotal = salesHistory[i].getQuantity() * salesHistory[i].getPrice();
        if (currentSaleTotal > salesHistory[maxSaleI].getQuantity() *salesHistory[maxSaleI].getPrice()) {
            maxSaleI = i;
        }
    }
    return salesHistory[maxSaleI];
}

Exercise. The most amount of products

Statement

Construct the code for the method "productMostSoldAtOnce" that finds the sale that had most elements of sold in one sale (quantity) and returns the productCode of that sale.

Solution

public int productMostSoldAtOnce(){ double max = salesHistory[0].getQuantity(); int MSI= 0; for (int i = 1; i<salesHistory.lenth; i++){ if max<salesHistory[i].getQuantity(){ max = salesHistory[i].getQuantity(); MSI=i; } } return salesHistory[MSI].getproductCode(); }

Features

If we want to summarize the features of OOP we can go with

  • Encapsulation. (already discussed) This enhances modularity.
  • Inheritance. Allows new classes to be derived from an existing class. So we can save time. (has it's nuances, though)
  • Polymorphism (method overload)

Polymorphism (method overload)

In a class we can define more than one method with the same name. But to distinguish from one method from other, they need to have different parameters.

Classic example 1:

If we have the class Calculator we can have a mehtod public double multiply(double a, double b), and a method to multiply 3 numbers public double multiply(double a, double b, double c) or even an array public double multiply(double[] array).

Remember that here we're talking about the signature of the method, not the implementation

The compiler would tell which one to use from how many parameters (and types are send to the method)

Advantages of polymorphism

  • Same name but diffent parameter list
  • We can have unique actions in subclasses (child classes)
  • Provides decoupling. We can have a common interfce and hides the implementation.

Adavantadges of inheritance:

Lexicon of inheritance

Using this context of UML diagrams

imagen

In this context the dependency of Person and Professor (or student) is inheritance and also, like all the dependencies is directional. All Professor instances are Person but not the other way around. Person is called the parent class and Professor the child class.

Another name to the child class is subclass.

Also we can say that class Professor extends the class Person. It's also what we have to write in java to mark this.

public class Professor extends Person {
    private int salary; 
    
    // constructor not written
    
    public int getSalary() {
        return this.salary;
    }
    
    public void setSalary(int salary){
        this.salary = salary;
    }
}

(page 315)

  • Extensibility. We can add new data or actions that doesn't exist in the parent class. In the case of Professor we can implement new methods "giveClass()" that doesn't exist in the parent class (Person).

  • Reusability. This means that child classes can use private methods and elements from parent classes.

    In the example of Professor we can write in a Main class this code

    Professor professor = new Professor(/*Parameters */);
    professor.getName(); //this will return a name 

The method getName works even if we didn't define it in Professor because already exists.

  • Information hiding

We can state in the parent class what are the methods available to the child classes.

  • Overriding of actions

In some cases we can also override methods from the parent class. The example is with Animals

imagen

In this context a animal can Sound but a Dog and a Parrot will sound differently. They can have different implementations of the method sound.

Reference:

https://www.w3schools.in/java/method-overriding

Method signature

Method signature is the combination of
2) name
3) list of parameters (with types)

image

In this example with this snippet (snippet is a small fragment of code)

public boolean StartsWithAuthor(String au){ for (int=0; int < library.length; i++){ if (library[i].getAuthor().startsWith(au)){ return true; } } return false; }

the method signature would be:

StartsWithAuthor(String au)

In some other contexts signature of a method is informally called to all the line of the definition of a function (so it includes the return type, access modifier and such). But for this purpose this is not what we have to rlearn.

Implementation of a method

The implementation of a method is what is written between the curly braces {}

In the last example it would be

for (int=0; int < library.length; i++){ if (library[i].getAuthor().startsWith(au)){ return true; } } return false;

Disadvandages of OOP

OOP is very complex. For fast prototyping is way too much. It increases complexity so is usually better suited for long projects.

Example of adding elements in an array

We are in a context of Department and Book

Recipee example

Construct the basics of a POJO

Remember that a POJO is a Plain Old Java Object, an object with attributes, accessors, mutators and the constructor

One example is that given some context you need to create the classes, the accessors, the constructor and the mutators.

This is the context

We have a cooking application that models recipes. In order to do that, we are using 2 classes.

The class Recipe has the following variables:

  • minutesToPrepare, a variable that stores how many minutes need the recipee to be prepared
  • instructions, a chain of charactes that holds the (short) instructions for the recipee
  • name that holds the name of the recipe
  • ingredients that holds several objects of the type Ingredient, up to 25.
  • numberOfIngredients a number that holds how many ingredients has the particular recipee.

The class Ingredient has the following variables

  • name that holds the name of the ingredient
  • quantity a number that holds the quantity that is necessary for that particular recipee
  • units a name of the units of the quantity because it can be in mililiters or grams.
  • vegan a variable that can specify if the specific ingredient is vegan or not.

These 2 classes also have one constructor each. In the case of Recipe it's going to ask for the minutesToPrepare, the name and the instructions. In the case of Ingredient it's going to ask for the 4 attributes.

Construct both classes with their constructors, accessor methods and mutator methods.

Solution

Recipe

public class Recipe { //start with the attributes private int minutesToPrepare; private String name; private int numberOfIngredients; private Ingredient[] ingredients = new Ingredient[25]; // why the brackets: because it's an array // why not String[]: because the statement says that is a object of the type Ingredient // why the initialization: because it has to be up to 25 (also in the statment) private String instructions; //constructor public Recipe(String name, int minutesToPrepare, String instructions) { //why this 3 parametes: because the statement says so this.name = name; this.minutesToPrepare = minutesToPrepare; this.instructions = instructions; //why the use of this keyword? //because we need to differenciate the instance attribute and the parameter variable. } //accessors public String getName(){ return this.name; } public int getMinutesToPrepare(){ return this.minutesToPrepare; } public String getInstructions(){ return this.instructions; } public int getNumberOfIngredients(){ return this.numberOfIngredients; } public Ingredient[] getIngredients() { return this.ingredients; } //mutators public void setName(String i){ this.name = i; } public void setMinutesToPrepare(int y) { this.minutesToPrepare = y; } public void setInstructions(int z) { this.instructions = z; } public void setNumberOfIngredients(int numberOfIngredients){ this.numberOfIngredients = numberOfIngredients; } }

Ingredient

credit M.Z and K.B.

public class Ingredient { private String name; private int quantity; private String units; private boolean vegan; public Ingredient(String name, double quantity, String units, boolean vegan) { this.name = name; this.quantity = quantity; this.units = units; this.vegan = vegan; } public String getName() { return name; } public double getQuantity() { return quantity; } public String getUnits() { return units; } public boolean isVegan() { return vegan; } //mutators Setters public void setName(String name){ this.name = name; } public void setQuantity(int y) { this.quantity = y; } public void setUnits(String z) { this.units = z; } public void setVegan(Boolean w) { this.vegan = w; }

Usually in the exams these solutions with arrays don't allow other classes to access to the array directly, they use a couple of methods that in this case would be getIngredient (in singular) and addIngredient.

Construct method that evaluates the whole object

Let's have a method in the class Recipe that is going to return if that recipe is vegan or not.

Construct a method isVegan in the class Recipe that is going to return if the recipe is vegan or not.

Solution:

public boolean isVegan() { boolean vegan = true; for (int x = 0; x < this.numberOfIngredients; x++){ if (this.Ingredients[x].isVegan()==false) { vegan = false; break; } } return vegan; }

Algorithms that you need to know how to implement in java

(From Paper1 topic 4)

//TO-DO by the students

Bubble sort

Let's say that we have a couple of POJOs, one is Car and the othere is Parking. Parking has an array of Cars and for some reason we want to order them by plate (that it's a String) using a method called "sortCars()" implemented in the Parking class.

public void sortCars(){ //in this case I guess that the array of cars has the original name of cars for (int i = 0; i< cars.length -1; i++) { for (int j = i; j < cars.length; j ++){ //check adjacent if (cars[j].getPlate() > cars[j+1].getPlate()) { //swap Car temp = cars[j]; cars[j] = cars [j+1]; cars[j+1] = temp; } } } }

Selection sort

//TO-DO by the students