25% developed

Object-Oriented Programming

From Wikibooks, open books for an open world
Jump to navigation Jump to search
Object-Oriented Programming Languages

Development stage: 00% Java

Development stage: 00% PHP

Development stage: 00% Python

Development stage: 00% C++

Object-Oriented Programming (OOP) is a way of designing programs and structuring your code. It is different from the functional programming paradigm which you might have used until now. The OOP paradigm allows you to define Objects that have specific behaviors in order to abstract and mimic "real life" behaviors. In OOP we focus mostly on the "what", meaning the functionalities of the Objects, rather than the "how", the algorithmic implementations of specific functionalities. Thus the design of programs will focus first on behaviors needed, to make sure the program structure is right, and then on the implementation details.[1]


Note

Java is the programming language you will be studying for this option. You will be required to read and write Java code on paper during the Paper 2 Exam.



Objects as a programming concept[edit | edit source]

What is an object?[edit | edit source]

D.1.1 Outline the general nature of an object

Objects represent a concept, an idea, or any entity in the physical world. For example, a player, a game board, a die, etc. These objects will have properties of their own. For example, a die can be rolled and give a number, but the board cannot. The interaction between objects via their properties and their relations allows us to better model complex problems in independent code structures.

In Java, objects are defined in classes using the class keyword. Here we created the User class.

class User {
    
}

Objects consist of two things:

  • Attributes: The parameters of objects. For example, a user's name, user language, user subscription,...
  • Methods: The functions and behaviors of objects. For example, a user can greet someone, ask a question, make a reclamation,...


Let's add a name attribute and a greet() method to our "User" object.

class User {
    // The attribute
    private String name;
    
    // The method
    public void greet(){
        System.out.println("Hello");
}


Note

The public and private keywords are explained under the Encapsulation section


Now, let's see how to create and use our object. However, before we get to that, we need to define a special method, called the constructor. The constructor method will allow us to create instances of our objects. An instance of a class means an actual object that has its own memory location and that can be used.

Constructor methods are called when we initialize a new instance of an object. They allow us to set initial values for our attributes.

Constructor methods always have the same name as our class name and cannot have a return type. Here is a demo:

class User {
    // The attribute
    private String name;
    
    // The constructor
    public User(String name){
        this.name = name;
    }
    
    // The method
    public void greet(){
        System.out.println("Hello" + " " + this.name);
    }
}

Note that all classes have constructors by default: if you do not create a class constructor yourself, Java creates one for you. However, in that case, you are no longer able to set initial values for object attributes. This means that we could create a User() here, but we could not set its name upon instantiation.

We can also note the use of the keyword this. The this keyword refers to the current object in a method or constructor. (The most common use of the this keyword is to eliminate the confusion between class attributes and parameters with the same name, for example when a class attribute is shadowed by a method or constructor parameter.)[2]

Now let's instantiate our User object:

class Main {
    public static void main(String[] args) {
        // Instantiating a User Object with name "John"
        User u = new User("John");
        
        // Using the User's method greet()
        u.greet();
    }
}

In this code, we are not in the User class. We wrote our code in the main() method, which acts as an entry point to your program for Java and is the method that is going to be executed when your program is run, inside the Main class.

You can also see that we used the new keyword to create our User instance, u. This syntax is similar to what we would use when instantiating reference types in Java. Defining a class could thus be seen as writing your own, user-defined, reference type. The User("John") after the new keyword is the call to the constructor method with the name parameter being "John" here.

After we instantiated our User u, we used its available method greet() with the dot notation.

If we compile both our User.java and Main.java files and then run our compiled Main.java file, then we see the following result on our terminal:

Hello John

D.1.2 Distinguish between an object (definition, template, or class) and instantiation.

To use an object or class it is necessary to instantiate the object first (unless using a static class). Instantiating a class means creating a location in memory for the object. The values contained inside an object will be individual to each instance of the object. Each instance of the class will usually have the same functions but these can behave differently based on the individual values of the attributes.

Accessor and mutator methods[edit | edit source]

D.1.10 Describe how data items can be passed to and from actions as parameters.

In our previous example, we used the constructor method to pass a value, 'John', to be set to our attribute name, in our User class.

But what if we want to modify that name later on? (Maybe we made a spelling mistake.) To easily modify attributes, we usually define accessor and mutator methods (these methods are also sometimes called getter and setter methods).

They look something like this:

class User {
    // The attribute
    private String name;

    // The constructor
    public User(String name) {
        this.name = name;
    }
    
    // The accessor method
    public String getName() {
        return this.name;
    }
    // The mutator method
    public void setName(String newName) {
        this.name = newName;
    }
    
    // The greet method
    public void greet() {
        System.out.println("Hello" + " " + name);
    }
}

By convention, we usually define the accessor's method name with 'get' + the name of the attribute we want to get. Similarly, for defining the mutator's method name we use 'set' + the name of the attribute we want to change. However, if there is a naming that makes the code clearer to read and easier to understand, we can deviate from that naming convention.

We could use the accessor and mutator methods on our Main class like so:

class Main {
    public static void main(String[] args) {
        // Instantiating a User Object with name "John"
        User u = new User("John");
        
        // Checking our current name attribute
        System.out.println(u.getName());
        
        // Changing our current name attribute
        u.setName("Jonathan");
        
        // Using our greet() method
        u.greet();
    }
}

This would output:

John
Hello Jonathan

In OOP, methods such as constructors, accessors and mutators are the preferred way to modify attributes of an object. They allow for more flexibility than deleting and recreating an instance and they also allow better encapsulation, which we will see in the following sections.

D.1.8 Construct related objects for a given problem.

Exercise

Imagine you want to code a digital clock app:

  • What attributes would the Clock object have?
  • What methods would the Clock object have?
  • Open an IDE and try to code this clock object.
  • Does a clock object already exist in the standard Java library?

Decomposing a problem into several objects[edit | edit source]

D.1.5 Describe the process of decomposition into several related objects.

Decomposition in computer science, also known as factoring, refers to the process by which a complex problem or system is broken down into parts that are easier to conceive, understand, program, and maintain. Object-oriented decomposition breaks a large system down into progressively smaller classes or objects that are responsible for some part of the problem domain.

There isn't "one" method for achieving the best OOP structure ever for your problem, but there are design processes that can be applied to help. Most of these processes can be seen in Topic 1, such as iterative development, agile development, test-driven development, ...

Using UML to represent your objects and their relationships is also an essential part of the design process. (see below)

D.1.6 Describe the relationships between objects for a given problem.

In order to be able to develop solutions to complex problems we will need to define different objects during a project and these Objects will interact with each other.

Objects mostly have three kinds of relationships:

  • the "has-a" relationship, means that an attribute of a class will be an instance of another. For example, a Book object will have an Author object or a HighSchoolClass object will have Students and a Teacher.
  • the "is-a" relationship, also called Inheritance, means that one Object is a subcategory of another object. It is a more precise definition of an over-category. For example, a Student Object extends the Human Object, a Car Object extends the Vehicle Object or a Dog Object extends the Animal Object.
  • the "uses-a" relationship, means that one object will use an instance of a class during one of its methods. For example, a Student Object might use a Book object while reading(), a Shelf Object might use a drill during building(), and a Human Object might use a Swimsuit Object and Towel Object during swimming().

Let's see some code examples of these three relationships.

The "has-a" relationship[edit | edit source]

Let's use the example of a Book object that will have an Author object as an attribute. Let's first define our Author class:

class Author {
    private String firstName;
    private String lastName;
    
    public Author(String firstName, String lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }
    
    public String getName(){
        return firstName + " " + lastName;
    }
}

Now let's define our Book class:

class Book {
    private String title;
    private int year;
    private Author author; //has-a relationship

    public Book(String title, int year, Author author) {
        this.title = title;
        this.year = year;
        this.author = author; // the Auhtor instance will be given in the constructor method
    }

    public void getBookInfos(){
        String infos = String.format("The book \"%s\" was written by %s" + " in %d",
                this.title, this.author.getName(), this.year); // we use the Authors's method getName() here
        System.out.println(infos);
    }

    public static void main(String[] args) {
        //We directly construct our author instance while constructing the book instance
        Book b = new Book("Nineteen Eighty-Four", 1949, new Author("George", "Orwell"));
        b.getBookInfos();
    }
}

If we compile both our Book.java and Author.java and then run our Book.class file (as it is the one that has the main() method) we will get the following output:

The book "Nineteen Eighty-Four" was written by George Orwell in 1949

Exercise: Try to define a "has-a" relationship between a HighSchoolClass Object, a Students Object, and a Teachers Object. Hint: you might want to define a Students Object that contains several Student objects. This is called an aggregate class (for Students).

The "is-a" relationship[edit | edit source]

Let's use the example of the Student class that extends the Human class.

For that, let's define a very simple Human class. This Human class has one attribute name and one method greet().

class Human {
    protected String name;

    public Human(String name) {
        this.name = name;
    }

    public void greet(){
        System.out.printf("Hello I am %s%n",this.name);
    }
}

Now if we define the Student class, as a subclass of Human (because all students are humans) this means that the Student class will have access to both the name attribute and the greet() method without having to redefine them. The Student class is also allowed to have additional attributes or methods.

To express the "is-a" relationship from Human to Student we use the extends keyword when defining the subclass.

So our Student class would look like this:

class Student extends Human {
    private String school;

    public Student(String name, String school) {
        super(name); // we refer to the superclasse's constructor
        this.school = school;
    }

    public void studentGreet(){
        System.out.printf("Hello I am student %s from %s.%n",this.name, this.school);
    }

    public void transfers(String newSchool){
        this.school = newSchool;
    }


    public static void main(String[] args) {
        Human h = new Human("Lisa");
        h.greet();

        Student s = new Student("Zara", "H4");
        s.greet(); //uses the Human method greet()
        s.transfers("EJM");
        s.studentGreet(); // uses the Student method studentGreet();
    }
    
}

When we compile and then run our Student.java code we get:

Hello I am Lisa
Hello I am Zara
Hello I am student Zara from EJM.

Note that we could also have chosen to call our Student method studentGreet(), greet() instead. In that case, a Student object will always execute the student version of the greet() method and not the Human version. This is called overriding. We will study more aspects of Inheritance in the dedicated section.

Exercise: Try to define a "is-a" relationship between an Animal class and a Bird class.

The "uses-a" relationship[edit | edit source]

Let's study an example of a Student Object that is using a Book object in one of its method reading(). First, let's define the Book class:

class Book {
    String title;
    int currentPage = 1;

    Book(String title) {
        this.title = title;
    }
    String getTitle(){
        return this.title;
    }

    int getCurrentPage(){
        return this.currentPage;
    }

    void setCurrentPage(int newPageNumber) {
        this.currentPage = newPageNumber;
    }
    
}

The Book Object is quite simple, it stores a book title and we have accessors and mutators around the book title and the page we are currently at. Now let's define the Student class. The Student will have a method reading() that will use a Book object to work.

class Student {
    String name;

    Student(String name) {
        this.name = name;
    }

    void reading(Book b){
        System.out.printf("Currently reading \"%s\" at page %d.%n", b.getTitle(), b.getCurrentPage());
        b.setCurrentPage(b.getCurrentPage() + 1);
    }

    public static void main(String[] args) {
        Book b = new Book("Clean Code");
        Student s = new Student("Lisa");
        s.reading(b);
        s.reading(b);
        s.reading(b);
    }
}

So now if we compile and run our Student.java code we get the following output:

Currently reading "Clean Code" at page 1.
Currently reading "Clean Code" at page 2.
Currently reading "Clean Code" at page 3.

But why is the Book object an argument of the method reading() and not stored as an attribute? Well, the Book is not an essential part of the Student, it does not define a property of the Student. It is used occasionally for a specific task, so it's better to pass it as an argument.

It is also interesting to note that the b.setCurrentPage(b.getCurrentPage() + 1); is not very explicit in what it is doing. Defining a method turnPage() could have been easier to read and a better "clean code" practice here.

Exercise: Try to define a "uses-a" relationship between a Human class and a Bike class in a commuting() method.

UML[edit | edit source]

Note

The creation of UML was originally motivated by the desire to standardize the disparate notational systems and approaches to software design. It was a synthesis of previous object modeling languages (Booch, OMT, OOSE) and is mainly the result of the work of Grady Booch, James Rumbaugh and Ivar Jacobson. It was developed at Rational Software in 1994–1995, with further development led by them through 1996. In 1997, UML was adopted as a standard by the Object Management Group (OMG), and has been managed by this organization ever since. In 2005, UML was also published by the International Organization for Standardization (ISO) as an approved ISO standard. Since then the standard has been periodically revised to cover the latest revision of UML



The Unified Modeling Language (UML) is a graphical modeling language based on pictograms and visual elements. It is designed to be a standardized method of visualization in the fields of software development and object-oriented design.

UML was designed to support the software development process throughout all of its life cycle. Its thus provides lots of diverse diagram templates such as deployment diagrams, use-case diagram, timing diagram, etc..... The one we are interested in, for OOP and the IB diploma, is the class diagram. It describes the structure of a system by showing the system's classes, their attributes, methods, and the relationships among objects.

Let's look at the different graphical elements used in class diagrams.

The class element[edit | edit source]

The class element structure in UML

In the diagram, classes are represented with boxes that contain three compartments:

  • The top compartment contains the name of the class. It is printed in bold and centered, and the first letter is capitalized.
  • The middle compartment contains the attributes of the class. They are left-aligned and the first letter is lowercase.
  • The bottom compartment contains the operations the class can execute. They are also left-aligned and the first letter is lowercase.

Visibility of elements[edit | edit source]

An example of a Book Class in UML with attributes and methods.

To specify the visibility of a class member (i.e. any attribute or method), these notations must be placed before the members' name:

+ Public
- Private
# Protected
~ Package

The above UML diagram is of class "Book", with two private attributes: "title" of type String and "currentPage" of type int, defaulting to value of 0. Two methods are part of the class, "turnPage" and "getTitle", both taking no parameters.

Relationships between objects[edit | edit source]

Examples of UML Relationships arrows

UML defines the following relationships:

  • Association: means that one class is using an instance of another class. It is a form of "has-a" relationship. You can recognise association when you see an attribute being an instance of another class. For example a Music object will have an instance of a Guitar Object as attribute so it can use the guitar in its methods to produce a music. It is depicted with a simple black arrow going out from the class that uses the other class.
  • Aggregation: means that one class has a collection of several instances of an other class. It is a form of "has-a" relationship. For example a Class will consist of several Student instances. Aggregation can be recognised when you have an attribute that is a collection of instances of another class. Aggregation is noted in UML with an open diamond towards the class that has the multiple instances of the other class.
  • Inheritance: means that a superclass/subclass relationship is happening. It is a form of "is-a" relationship. Refer to the section below to learn more about inheritance. It is depicted with a white arrow going pointing towards the superclass and originating from the subclass.
  • Dependency: means that one class depends on another for a specific action. It is a form of "uses-a" relationship. For example a Student object needs an instance of Swimsuit in order to go swimming. Dependency can be recognised in code as an instance of another class being used as a parameter of a method. It is depicted with a simple black arrow with a dashed line going out from the class that uses the other class.





Ressource

A video explanation of UML: https://www.youtube.com/watch?v=UI6lqHOVHic

To draw your own UML diagrams: https://app.diagrams.net/


D.1.3 Construct Unified Modelling Language (UML) diagrams to represent object designs.

Exercise: Draw the UML class diagram of the following project: https://home.uia.no/hallgeir/Java_Programmering/BokProsjekter/projects/chapter14/taxi-company-stage-one/. You can omit the test classes from your diagram.


D.1.4 Interpret UML diagrams.

Exercise: Write the java code for the following UML diagrams.

Example of UML diagram
Example of UML diagram


Correction for the "uses-a relationship"
class Bike{
    private String model;
    private float speed;

    public Bike(String model, float speed) {
        this.model = model;
        this.speed = speed;
    }

    public String getModel() {
        return model;
    }

    public float getSpeed() {
        return speed;
    }
}
class Human {
    private String name;

    public Human(String name){
        this.name = name;
    }

    // this method is our "uses-a" relationship (or association in UML)
    public void commuting(Bike myBike){
        System.out.printf("Currently riding a %s bike at %f km/h !%n", myBike.getModel(), myBike.getSpeed());
    }

    public void greet(){
        System.out.printf("Hi I'm %s !", this.name);
    }
}
public class Main {
    public static void main(String[] args) {
        // instance 1 of Bike class
        Bike myBike = new Bike("electric", 25); 

        // instance 2 of Bike class
        Bike rental_bike = new Bike("velib", 18.2f); 

        // instance of Human
        Human h = new Human("Lisa"); 
        h.greet(); 

        // using a first bike to commute
        h.commuting(myBike); 
        System.out.println("Arrived at work ! Catching my breath ...");
        // using another bike to commute
        h.commuting(rental_bike); 
        System.out.println("Arrived home! Catching my breath ...");
    }
}

output:

Hi I'm Lisa !Currently riding a electric bike at 25,000000 km/h !
Arrived at work ! Catching my breath ...
Currently riding a velib bike at 18,200001 km/h !
Arrived home! Catching my breath ...


D.1.7 Outline the need to reduce dependencies between objects in a given problem.

  • It increases maintenance overheads
  • Maintenance overheads refer to the changes that need to be made to the entire system if you make a change to a component.

For example if you change, B, it affects how C, D and E works, implying that you have to spend time fixing them to work with the “new” B. 

D.1.9 Explain the need for different data types to represent data items.

  • char: smallest addressable unit of the machine that can contain basic character set. It is an integer type. Actual type can be either signed or unsigned depending on the implementation.
  • int: basic signed integer type. At least in the [−32767,+32767] range, thus at least 16 bits in size.
  • float: single precision floating-point type. Actual properties unspecified (except minimum limits), however on most systems this is the IEEE 754 single-precision binary floating-point format.
  • string: holds sequences of unsigned 16-bit (2-byte) code points that range in value from 0 through 65535. Each code point, or character code, represents a single Unicode character. A string can contain from 0 to approximately two billion (2 ^ 31) Unicode characters.


Features of OOP[edit | edit source]

Encapsulation[edit | edit source]

D.2.1 Define the term encapsulation.

Encapsulation is defined as the "process of wrapping code and data together into a single unit". But what does that mean ? In a practical manner, encapsulation is achieved by setting the right level of access to attributes and methods. You can see it as a protective shield for an object: we protect the inner mechanisms and only reveal certain methods that the public can use. This is the same as when you start your computer, the "on" button abstracts all the start up processes happening in the background that the user doesn't see. The end user doesn't care about the details of implementations and shouldn't be bothered with.

To achieve encapsulation we have the following access modifiers to our dispositions. These can be set for both attributes and methods and should be explicit, rather than using the default access modifier.

  • Private: most restrictive keyword; Can only be accessed within the declared class
  • Protected: When declared, can only be accessed by the subclasses in another package or any class within the member class
  • Public: Can be accessed from any other class. It is the least restrictive keyword.
  • Default: If you don't specify any access modifier then the code is only accessible to classes in the same package. If you didn't declare any package this means your code is only accessible in your current project.

In most cases, we will want to set the attributes private and the accessors and mutators public. (Indeed this allows for more control over the modifications done to attributes (no direct modifications) and helps with debugging, managing unwanted behaviors and cleaner readable code.)

Let's use our first User example to examine the behaviors of these access modifiers.

Public attributes

class User {
    public String name;
    
    public User(String name){
        this.name = name;
    }
    
    public void greet(){
        System.out.println("Hello" + " " + this.name);
    }
}
class Main {
    public static void main(String[] args) {
        User u = new User("Lily");
        u.name = "Joshua";
        u.greet();
    }
}

When compiling and running our Main.java we get the following output:

Hello Joshua

Having a public attribute means we can directly change the value of the attribute u.name = "Joshua" from another class.

Private attributes

If we try to compile and run the same Main.java but with the attribute private String name; in User.java we get the following error:

java: name has private access in User

Indeed if an attribute is private then it means we can not modify it directly from another class. We would have to use public accessor and mutator methods if available. We can however still use the attribute inside it's class, as we are doing in the greet() method.

Private methods

If we turn our greet() method private in Student.java and try to call u.greet() in our Main.java file we get the following error:

java: greet() has private access in User

Indeed if the greet() method is private then it means it can not be accessed by any classes outside itself. The only ways we could use a private method would be in another method inside the same class or if the main() method was running from that class.

Public methods Public methods are accessible from external classes and behave "in the expected way";

D.2.4 Explain the advantages of encapsulation.

Encapsulation provides several advantages:

  • It provides data hiding, this means that access to certain informations is controlled and restricted. That way the user (other classes) will only see available actions at its level and does not need to bother with implementation details. The data management of attributes is thus hidden away.
  • It provides better control over the data management as fewer unexpected behaviors can arise if user actions are limited.
  • It Increases usability by keeping data private and providing public well-defined service methods the role of the object becomes clear to other objects.
  • It provides flexibility as we can change access modifiers depending on our needs and depending on the use cases.
  • It helps us to have code that is easily testable through unit testing.
  • It make the code more reusable as we essentially care about what methods are present and less about the implementation. We can change an implementation of a method without changing the code the code structure. It promotes maintenance, as code changes can be made independently.

Inheritance[3][edit | edit source]

D.2.2 Define the term inheritance.

Inheritance is a concept where a subclass (also known as child class or derived class) inherits from a superclass (also known as parent class or base class). The subclass is a class that will describe a more precise kind of object that the superclass does. The subclass can have access to methods and attributes of the superclass.

Lets use our superclass Human and subclass Student from before.

class Human {
    protected String name;

    public Human(String name) {
        this.name = name;
    }

    public void greet(){
        System.out.printf("Hello I am %s%n",this.name);
    }
}
class Student extends Human {
    private String school;

    public Student(String name, String school) {
        super(name); // we refer to the superclasse's constructor
        this.school = school;
    }

    public void studentGreet(){
        System.out.printf("Hello I am student %s from %s.%n",this.name, this.school);
    }

    public void transfers(String newSchool){
        this.school = newSchool;
    }


    public static void main(String[] args) {
        Human h = new Human("Lisa");
        h.greet();

        Student s = new Student("Zara", "H4");
        s.greet(); //uses the Human method greet()
        s.transfers("EJM");
        s.studentGreet(); // uses the Student method studentGreet();
    }

}

When we compile and then run our Student.java code we get:

Hello I am Lisa
Hello I am Zara
Hello I am student Zara from EJM.

Here, the Student class is a subclass of Human (because all students are humans). Because of the access modifiers, the Student class will have access to both the name attribute and the greet() method without having to redefine them here. Indeed a subclass does not inherit the private members of its parent class. Only public or protected members are inherited. However, if the superclass has public or protected methods for accessing its private attributes, these can also be used by the subclass.

The Student class is also allowed to have additional attributes or methods. Here Student has an additional schoolName attribute and two additional methods: transfers() and studentGreet()

To define a subclass we use the extends keyword. The keyword is only used in the subclass and not in the superclass. Here class Student extends Human

Constructors are not members of a class, so they are not inherited by subclasses, but the constructor of the superclass can be invoked from the subclass. To achieve this we make use of the keyword super. The super keyword allows us to access attributes, methods and constructors from the superclass. Here in our Student constructor we refer to Human's constructor by calling super(name).


Ressource

To learn more about the super keyword: https://www.programiz.com/java-programming/super-keyword


A subclass can also be superclass for another subclass. This is called multilevel inheritance. For example we could have: Student that extends Human that extends Mammal that extends Animal. Here Human would be the subclass for Mammal but the Human would also be the superclass for Student. In Java classes only support single inheritance so we can only extend one class at the time (we would write class Student extends Human and not class Student extends Mammal extends Animal. To see that global inheritance pattern, UML diagrams are very useful.

A superclass can be extended by multiple classes. This is called hierarchical inheritance. For example the Human class can be extended by the Student class but the Human class could also be extended by the Teacher class at the same time. Again, to see that global inheritance pattern, UML diagrams are very useful.

Overriding[edit | edit source]

Note

When overriding a method using the @Override annotation is a good clean code practice as it make the overriding obvious and less sneaky



Overriding happens when we define an attribute or a method in the subclass, with the same name than in the superclass. If that happens then the attribute or method of the superclass is hidden and cannot be accessed by an instance of the subclass anymore.

For example if we had defined studentGreet() as greet() instead in our Student Class, then every time we call the greet() method on a Student instance we will get a message with the name + the school of the student. From a Student instance we would not be able to have a greeting message with the name of the student only, anymore. From a Human instance however we would get the greeting message with the name only, when calling greet().

Overriding is useful when a subclass needs a more precise definition of a certain behavior than in the superclass.


Ressource

To learn more about annotations in Java: https://www.programiz.com/java-programming/annotations


Exercise: Rename the studentGreet() method as greet() and then try calling this method from a Student instance and then form a Human instance. What happens ?

Casting[edit | edit source]

Note

All java objects descend from the Object type.


Since a Student object is also a Human object, a Student object can be used when a Human object is wanted. On the other hand a Human object can not be called instead of a Student Object. Nothing would prevent us from writing: Human n = (Human) s with s being a Student instance. The explicit casting is not even mandatory here. Casting from a subclass to a superclass is called upcasting.

Exercise: Try to implement Teacher class as a subclass of Human

D.2.5 Explain the advantages of inheritance.

The main advantage of inheritance is that is allows for code reusability. The code from the superclass doesn't need to be rewritten in the subclass, hence saving us a lot of time and avoiding code duplication and thus mistakes.

Overriding is also a big advantage as it provides modularity to cover more inheritance cases. Indeed details of superclasses can hidden to only focus on the current, more specific, behavior of the subclass. Method overriding is also known as runtime polymorphism.

Polymorphism[edit | edit source]

D.2.3 Define the term polymorphism.

Polymorphism is a way of accessing multiple object of different types in the same way. To do this you make use of a polymorphic type that can be accessed in a way that also applies to all the other types of the objects. This is often used in combination with inheritance where multiple different child classes can be accessed as a parent class type and providing access to all features from the parent class or features that have been overloaded by the child class. Polymorphic child classes do not allow access to added features of the child class.

D.2.6 Explain the advantages of polymorphism.

  • Same interface could be used for creating methods with different implementations
  • Reduces the volume of work in terms of distinguishing and handling various objects
  • Supports building extensible systems
  • Complete implementation can be replaced by using same method signatures

D.2.7 Describe the advantages of libraries of objects.

Libraries of objects can be imported to avoid "reinventing the wheel". Many common tasks that applications perform (such as sorting) already have well-tested libraries written to perform them. With permission, another developer's code can be shipped along yours to save development time. This also reduces the testing surface, as well-tested libraries are unlikely to have bugs.

D.2.8 Describe the disadvantages of OOP.

Objected oriented programs tend to have a much larger filesize than other programs. This was especially important in earlier times, where storage was limited, or in embedded systems were storage is still very limited. Objected oriented programs tend to be slower than linear programs, as the computer needs to traverse different classes and understand the relationships between them. OO programming languages tend to have a steep learning curve. Finally, object oriented programs tend to take more effort to create, as they require careful planning and conceptualization.

D.2.9 Discuss the use of programming teams.

Teams are set up to accomplish larger tasks as a group Advantages of the use of teams:

  • More members means more ideas, including ideas that might not have come about without a team
  • The strengths of some can cover up the weaknesses of others
  • With more "manpower" to work on problems, larger problems and projects could be taken on

Disadvantages of the use of teams:

  • If not handled properly, the weaknesses of some members could undermine the group as a whole
  • Different styles of programming and working have to learn to coincide and work together
  • Communication among members becomes a priority for the team by necessity

D.2.10 Explain the advantages of modularity in program development.

  • If a single procedure is developed it can be reused multiple times without having to retype the code
  • Programs can be designed more easily and more effectively due to the divisions of the entire code into sectors because a small team deals with only a small part of the entire code
  • Modular programming allows many programmers to collaborate on the same application
  • Code is stored across multiple files; code is also short, simple and easier to understand
  • Scoping of variables can be easily controlled
  • When errors are localized to a subroutine or function, they can be easily identified

Program development[edit | edit source]

D.3.1 Define the terms: class, identifier, primitive, instance variable, parameter variable, local variable.

Class: A class is the blueprint from which individual objects are created.

Identifier: Identifiers are the name of variables, methods, classes, packages, and interfaces. They are a way of referring to specific things.

Primitive: A value that is predefined by the language and is named to a reserved keyword.

D.3.2 Define the terms: method, accessor, mutator, consutrctor, signature, return value.

Method: A method is a part of a program that executes java code. It is not to be confused with a constructor method.

Accessor: An accessor method is a method that is used to obtain information about an object and is also used in order to access the data in that object

Mutator: A mutator method is a method that is used to set a value of a private field that cannot be publicly accessed.

Constructor: A constructor method is a method that creates one instance of a class

Signature: Refers to the method name and the number and type of its parameters. Return types and thrown exceptions are not considered part of the signature

Return value: It is the value or data type that is returned after a program has been run

D.3.3 Define the terms private, protected, public, extends, static.

Private: most restrictive keyword; Can only be accessed within the declared class

Protected: When declared, can only be accessed by the subclasses in another package or any class within the member class

Public: Can be accessed from any other class

Extends: This Java keyword is used when you want a class or object to inherit from another class or object.

Static: This keyword signifies that a member variable, or method, can be accessed without requiring an instantiation of the class to which it belongs.

D.3.4 Describe the uses of the primitive data types and the reference class string.

In examination questions the primitive types will be limited to int, long, double, char and Boolean.

Primitive data types are most commonly used to store simple values. They are also used as the building blocks of the more complex abstract data types.

Although String is not a primitive data type, it is considered a ‘basic’ type as it is used to store simple values. 

D.3.5 Construct code to implement assessment statements D.3.1 - D.3.4.

D.3.6 Construct code examples related to selection statements.

IF / ELSE Boolean conditions, e.g. WHILE list.hasNext()

D.3.7 Construct code examples related to repetition statements.

FOR loops WHILE loops

D.3.8 Construct code examples related to static arrays.

  • reading from an array
  • moving data to/from the array
  • printing out selections from it… etc.

D.3.9 Discuss the features of modern programming languages that enable internationalisation.

  • specialized text enablement
  • sorting behavior
  • date and time formatting
  • keyboard layouts
  • UTF-8 encoding
  • Use of common character sets among many platforms and languages, like UNICODE
  • Platform independent high level languages (like Java) enable code to run on many platforms

D.3.10 }Discuss the ethical and moral obligations of programmers.

  • Adequate testing of products to prevent possibilities of commercial or other damage
  • Acknowledging the work of other programmers (to avoid plagiarism)
  • Open Source movement
  • Robotics and artificial intelligence
  • Adequate testing of products to prevent possibilities of commercial or other damage
  • Acknowledging the work of other programmers (to avoid plagiarism)
  • Open Source movement
  • Robotics and artificial intelligence

Advanced program development[edit | edit source]

D.4.1 Define the term recursion.

D.4.2 Describe the application of recursive algorithms.

D.4.3 Construct algorithms that use recursion.

D.4.4 Trace recursive algorithms.

D.4.5 Define the term object reference.

D.4.6 Construct algorithms that use reference mechanisms.

D.4.7 Identify the features of the abstract data type (ADT) list.

D.4.8 Describe the application of lists.

D.4.9 Construct algorithms using a static implementation of a list.

D.4.10 Construct list algorithms using object references.

D.4.11 Construct algorithms using the standard library collections included in JETS.

D.4.12 Trace algorithms using the implementation described in assessment statements D.4.9 - D.4.11.

D.4.13 Explain the advantages of using library collections.

D.4.14 Outline the features of ADT's stack, queue, and binary tree.

D.4.15 Explain the importance of style and naming conventions in code.

  1. Java OOP Done Right Create object oriented code you can be proud of with modern Java Alan Mellor https://leanpub.com/javaoopdoneright
  2. https://www.w3schools.com/java/ref_keyword_this.asp
  3. https://docs.oracle.com/javase/tutorial/java/IandI/subclasses.html