Post

CS2103T Week 1

CS2103T Week 1 Topics

Rehash and review of topics based on the CS2103T website here.

Textbook: Software Engineering for Self-Directed Learners CS2103 Edition

Main topics are OOP: Classes & Objects, Inheritance, Polymorphism, Java Collections and Exception Handling.

OOP: Classes & Objects

Object-Orientated Programming (OOP) Programming Paradigm.

Programming paradigm guides analysis of problems and structure solutions in a specific way.

  • An object in OOP has state (data) and behavior (operations on data) similar to objects in the real world.
  • OOP views the world as a network of interacting objects.
  • OOP solutions seek to create a similar object network inside the computer’s memory so a similar result can be achieved programmatically.
  • OOP does not demand that the network follow the real world exactly.
  • Every object has an interface and an implementation.
  • Objects interact by sending messages.

The concept of Objects in OOP Is an abstraction mechanism as it allows abstracting away lower level details and working with bigger granularity entities.

An object is an encapsulation of some data and related behavior in terms of:

  • Packaging aspect: Object packages data and related behavior in a self-contained unit.
  • Information hiding aspect: Data in object is hidden and only accessible using object’s interface.

Relationship between Classes and Objects

Writing an OOP program is writing instructions the computer uses to

  • create the virtual world of the object network
  • provide it the inputs to produce the outcome.

A class contains instructions for creating a specific kind of objects.

Defining a class introduces a new object type.

  • A class definition is like a template for objects, specify attributes and methods of object.
  • new operator instantiates objects, creates new instance of a class.
  • Java convention is to use PascalCase format for class names.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// Class Definiton
public class Time {
    private int hour;
    private int minute;
    private int second;
}

// Class constructor
public Time() {
    hour = 0;
    minute = 0;
    second = 0;
}

//Overloaded Constructor
public Time(int h, int m, int s) {
    hour = h;
    minute = m;
    second = s;
}

//To initialize an instance variable:
Time time = new Time();
Time justBeforeMidnight = new Time(11, 59, 59);
  • code usually placed in a file whose name matches the class, e.g. Time.java
  • public classes can be used in other classes. Instance variables are private and can only be accessed from inside the Time class.

this keyword is a reference variable in Java that refers to the current object.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// Parameters shadow the instance variables, 
// 'this' keyword needed to tell them apart.
public Time(int hour, int minute, int second) {
    this.hour = hour;
    this.minute = minute;
    this.second = second;
}

// 'this' can be used to refer to a constructor of a class
public Time() {
    this(0, 0, 0); // call the overloaded constructor
}

public Time(int hour, int minute, int second) {
    // ...
}

Instance Methods Methods can be added to a class which can be used from the objects of that class.

  • instance methods do not have the static keyword in the method signature, and can access attributes of the class.
1
2
3
4
5
6
7
8
// Adding instance method to Time class:
public int secondsSinceMidnight() {
    return hour*60*60 + minute*60 + second;
}

// Using the method
Time t = new Time(0, 2, 5);
System.out.println(t.secondsSinceMidnight() + " seconds since midnight!");

Getters and Setters

  • Accessors/Getters: To access private attributes of instance variables, one can provide methods to access them.
  • Setters: To modify attributes of an object
1
2
3
4
5
6
7
8
9
// getter method
public int getHour() {
    return hour;
}

//setter method
public void setHour(int hour) {
    this.hour = hour;
}

Class-level Members

Each object has its own copy of the attribute value. However, some attributes can be maintained centrally, shared by all objects of the class. Similarly, methods can also be related to a specific class but not a specific object.

  • Such variables are called class-level attributes. (e.g. totalPersons for a Person class.)
  • Such methods are called class-level methods. (e.g. getTotalPersons())
  • Collectively, known as class-level members, or static members and are to be accessed using the class name rather than an instance of the class.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public class Bicycle {

    static final double PI = 3.141592653589793;
    private int gear;
    private int speed;

    // an instance variable for the object ID
    private int id;

    // a class variable for the number of Bicycle
    //   objects instantiated
    private static int numberOfBicycles = 0;

    public static int getNumberOfBicycles() {
        return numberOfBicycles;
    }
    
    public Bicycle(int startSpeed, int startGear) {
        gear = startGear;
        speed = startSpeed;

        numberOfBicycles++;
        id = numberOfBicycles;
    }
    ...
}
  • Class variables are referenced by the class name itself, as in Bicycle.numberOfBicycles This makes it clear that they are class variables.
  • Static methods should be invoked with the class name without creating an instance of the class, as in ClassName.methodName(args)
  • The static modifier, in combination with the final modifier, is also used to define constants.

Explanation of System.out.println(...): out is a class-level public attribute of the System class. println is an instance level method of the out object.

Enumerations

An Enumeration is a fixed set of values that can be considered as a data type.

  • Often useful when using a regular data type such as int or String that would allow invalid values to be assigned to a variable.
  • e.g. variable priority, of high medium and low levels. Declare as type int, use only values 0, 1, 2 to indicate. However, opens possibility of invalid value e.g. 5 being assigned.
  • Instead, we can define an enumeration type Priority having values HIGH, MEDIUM, LOW only, so the compiler can catch invalid values.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public enum Day {
    SUNDAY, MONDAY, TUESDAY, WEDNESDAY,
    THURSDAY, FRIDAY, SATURDAY
}

Day today = Day.MONDAY;
Day[] holidays = new Day[]{Day.SATURDAY, Day.SUNDAY};

switch (today) {
case SATURDAY:
case SUNDAY:
    System.out.println("It's the weekend");
    break;
default:
    System.out.println("It's a week day");
}
  • You can define an enum type by using the enum keyword
  • Because they are constants, the names of an enum type’s fields are in uppercase letters
  • While enumerations are usually a simple set of fixed values, Java enumerations can have behaviors too

OOP Inheritance

Inheritance is an OOP concept that allows defining a new class based on an existing class.

  • A class that is derived from another class is called a subclass.
  • Other names for Base class: Parent class, Superclass
  • Other names for Derived class: Child class, Subclass, Extended class
  • Every class has one and only one direct superclass (single inheritance), except the Object class, which has no superclass.

Implementation:

  • The keyword extends indicates one class inheriting from another.
  • A subclass inherits all the members (fields, methods, and nested classes) from its superclass.
  • Constructors are not members, so they are not inherited by subclasses, but the constructor of the superclass can be invoked from the subclass.
  • If your method overrides one of its superclass’s methods, you can invoke the overridden method through the use of the keyword super.
  • A subclass constructor can invoke the superclass constructor.

The java.lang.Object class defines and implements behavior common to all classes—including the ones that you write. In the Java platform, many classes derive directly from Object, other classes derive from some of those classes, and so on, forming a single hierarchy of classes.

A superclass is more general than the subclass, while the subclass is more specialized than the superclass.

  • Applying inheritance on a group of similar classes can result in the common parts among classes being extracted into more general classes.
    • e.g. Creating Person class as a superclass for Man and Woman.

Inheritance implies the derived class can be considered as a sub-type of the base class (and the base class is a super-type of the derived class), resulting in an is a relationship.

Inheritance relationships through a chain of classes can result in inheritance hierarchies (aka inheritance trees).

inheritanceTree

Inheritance Tree
  • Multiple Inheritance is when a class inherits directly from multiple classes. Allowed in some languages (Python, C++) and not in others (Java, C#).

Method overloading: multiple methods with the same name but different type signatures. * Used to indicate that multiple operations do similar things but take different parameters.

Type signature: The type signature of an operation is the type sequence of the parameters. Return type and parameter names are not part of the type signature.

Method overriding: when a sub-class changes the behavior inherited from the parent class by re-implementing the method. * Overridden methods have the same name, same type signature, and same return type.

Access modifiers Access level modifiers determine whether other classes can use a particular field or invoke a particular method.

Two levels of access control:

  1. At the class level:
    • public: the class is visible to all other classes
    • no modifier: same as public
  2. At the member level:
    • public : the member is visible to all other classes
    • protected: same as public
    • no modifier: same as public
    • private: the member is not visible to other classes (but can be accessed in its own class)

OOP Polymorphism

Polymorphism allows one to write code targeting superclass objects, use that on subclass objects, and achieve possibly different results based on the actual class of the object.

  • The ability of different objects to respond, each in its own way, to identical messages is called polymorphism.
  • E.g. classes Cat and Dog both subclasses of Animal class, code targeting Animal objects achieve different results depending on if it is a Cat or Dog object.

Java is a strongly-typed language which means the code works with only the object types that it targets.

  • Strong-typing can lead to unnecessary verbosity caused by repetitive similar code that do similar things with different object types.
  • Better way is to take advantage of polymorphism to write code that targets superclass to work with any subclass object.
  • Polymorphic code is shorter, simpler, more flexible.

Abstract Classes

Abstract class: A class declared as an abstract class cannot be instantiated, but it can be subclassed.

  • Declaring a class as abstract as a representation of commonalities among its subclasses, where does not make sense to instantiate objects of that class.
  • E.g. Animal class as generalization of subclasses Dog, Horse, etc.

Abstract method: An abstract method is a method signature without a method implementation.

  • A class with an abstract method becomes an abstract class because the class definition is incomplete (due to the missing method body). Not possible to create objects using an incomplete class definition.
  • In Java, an abstract method is declared with the keyword abstract and given without an implementation.
    • If a class includes abstract methods, then the class itself must be declared abstract.
  • An abstract class is declared with the keyword abstract. Abstract classes can be used as reference type but cannot be instantiated.
  • When abstract class is subclassed, subclass should provide implementations for all of the abstract methods in its superclass or else the subclass must also be declared abstract.
1
2
3
4
5
6
7
8
9
public abstract class Animal {

    protected String name;

    public Animal(String name){
        this.name = name;
    }
    public abstract String speak();
}

Interfaces

An interface: behavior specification i.e. a collection of method specifications.

  • If a class implements the interface, it means the class is able to support the behaviors specified by the said interface.
  • In SWE, acts as a “contract” that spells out how their software interacts, without knowledge of how it is written.
  • A class implementing an interface results in an is-a relationship, just like in class inheritance.

Implementation of Interfaces:

  • In Java, an interface is a reference type, similar to a class, mainly containing method signatures.
    • Defining an interface is similar to creating a new class except it uses the keyword interface in place of class.
  • Interfaces cannot be instantiated—they can only be implemented by classes.
    • When an instantiable class implements an interface, indicated by the keyword implements, it provides a method body for each of the methods declared in the interface.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public interface DrivableVehicle {
    void turn(Direction direction);
    void changeLanes(Direction direction);
    void signalTurn(Direction direction, boolean signalOn);
    // more method signatures
}

public class CarModelX implements DrivableVehicle {

    @Override
    public void turn(Direction direction) {
       // implementation
    }

    // implementation of other methods
}
  • An interface can be used as a type e.g., DrivableVehicle dv = new CarModelX();.
  • Interfaces can inherit from other interfaces using the extends keyword, similar to a class inheriting another.
  • Java allows multiple inheritance among interfaces. A Java interface can inherit multiple other interfaces. A Java class can implement multiple interfaces (and inherit from one class).
  • Interfaces can also contain constants and static methods.

How Polymorphism Works

Substitutability: Every instance of a subclass is an instance of the superclass, but not vice-versa. As a result, inheritance allows substitutability: the ability to substitute a child class object where a parent class object is expected.

Dynamic binding ( aka late binding): a mechanism where method calls in code are resolved at runtime, rather than at compile time.

  • Overridden methods are resolved using dynamic binding, and therefore resolves to the implementation in the actual type of the object.

Static binding (aka early binding): When a method call is resolved at compile time.

  • Overloaded methods are resolved using static binding.

Three concepts combine to achieve polymorphism: substitutability, operation overriding, and dynamic binding.

  • Substitutability: Because of substitutability, you can write code that expects objects of a parent class and yet use that code with objects of child classes. That is how polymorphism is able to treat objects of different types as one type.
  • Overriding: To get polymorphic behavior from an operation, the operation in the superclass needs to be overridden in each of the subclasses. That is how overriding allows objects of different subclasses to display different behaviors in response to the same method call.
  • Dynamic binding: Calls to overridden methods are bound to the implementation of the actual object’s class dynamically during the runtime. That is how the polymorphic code can call the method of the parent class and yet execute the implementation of the child class.

Java: Collections

A collection — sometimes called a container — is simply an object that groups multiple elements into a single unit.

  • Collections are used to store, retrieve, manipulate, and communicate aggregate data.

The collections framework is a unified architecture for representing and manipulating collections. It contains the following:

  • Interfaces: These are abstract data types that represent collections. Interfaces allow collections to be manipulated independently of the details of their representation.

    Example: the List<E> interface can be used to manipulate list-like collections which may be implemented in different ways such as ArrayList<E> or LinkedList<E>.

  • Implementations: These are the concrete implementations of the collection interfaces. In essence, they are reusable data structures.

    Example: the ArrayList<E> class implements the List<E> interface while the HashMap<K, V> class implements the Map<K, V> interface.

  • Algorithms: These are the methods that perform useful computations, such as searching and sorting, on objects that implement collection interfaces. The algorithms are said to be polymorphic: that is, the same method can be used on many different implementations of the appropriate collection interface.

    Example: the sort(List<E>) method can sort a collection that implements the List<E> interface.

A well-known example of collections frameworks is the C++ Standard Template Library (STL).

Core Collection Interfaces:

  • Collection — the root of the collection hierarchy. A collection represents a group of objects known as its elements.
    • The Collection interface used to pass collections around and to manipulate them when maximum generality is desired.
    • Some types of collections allow/disallow duplicate/ordered elements.
    • The Java platform doesn’t provide any direct implementations of this interface but provides implementations of more specific subinterfaces, such as Set and List. Also see the Collection API.
  • Set — a collection that cannot contain duplicate elements.
    • This interface models the mathematical set abstraction and is used to represent sets.
  • List — an ordered collection (sometimes called a sequence). Lists can contain duplicate elements.
    • The user of a List generally has precise control over where in the list each element is inserted and can access elements by their integer index (position).
  • Queue — a collection used to hold multiple elements prior to processing.
    • Besides basic Collection operations, a Queue provides additional insertion, extraction, and inspection operations.
  • Map — an object that maps keys to values. A Map cannot contain duplicate keys; each key can map to at most one value.
  • Others: Deque, SortedSet, SortedMap.

Java Classes: ArrayList, HashMap

  • ArrayList class is a resizable-array implementation of the List interface. API.
  • HashMap (note the PascalCase!) is an implementation of the Map interface. It allows you to store a collection of key-value pairs.

Exception Handling

Well-written applications include error-handling code that allows them to recover gracefully from unexpected errors.

  • When an error occurs, application either request user intervention / recover on its own / log off / shut down.

Exceptions: (exceptional event)

  • Used to deal with ‘unusual’ but not entirely unexpected situations that the program might encounter at runtime.

Three basic categories of Exceptions in Java:

  1. Checked exceptions: exceptional conditions a well-written application should anticipate and recover from.
    • All exceptions are checked exceptions, except for Error, RuntimeException, and their subclasses.
  2. Errors: exceptional conditions that are external to the application, and that the application usually cannot anticipate or recover from.
    • Errors are those exceptions indicated by Error and its subclasses.
  3. Runtime exceptions: conditions that are internal to the application, and that the application usually cannot anticipate or recover from.
    • Runtime exceptions are those indicated by RuntimeException and its subclasses. These usually indicate programming bugs, such as logic errors or improper use of an API.
  • Errors and runtime exceptions are collectively known as unchecked exceptions.

exceptionTree

Java Exception Types

How Exception Handling is done

After enconuntering “exceptional situation”:

  • encapsulate details of the situation in an Exception object
  • throw/raise object for another piece of code can catch it and deal with it.

More specifically:

  • execution error -> create an exception object -> hand to runtime system (called throwing)
  • exception object contains information about error (e.g. type, state of the program).
  • Exception thrown -> runtime system attempts to find something to handle it in the call stack. Searches call stack for a method that contains a block of code that can handle the exception. (Exception handler).
  • Search from method where error occurred, through call stack in reverse order of methods called.
  • When appropriate handler is found, runtime system passes the exception to the handler.
  • An exception handler is considered appropriate if the type of the exception object thrown matches the type that can be handled by the handler.
  • Exception handler chosen catches the exception. If runtime system does not find appropriate handler, terminates.

Advantages of exception handling in this way:

  • Ability to propagate error information through call stack.
  • Separation of code dealing with ‘unusual’ situations from main code.

Using Exceptions

A program can catch exceptions by using a combination of the try, catch blocks.

  • The try block identifies a block of code in which an exception can occur.
  • The catch block identifies a block of code, known as an exception handler, that can handle a particular type of exception.
  • Use a finally block to specify code that is guaranteed to execute with or without the exception.
  • Use the throw statement to throw an exception. The throw statement requires a throwable object as the argument.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public void writeList() {
    print("starting method");
    try {
        print("starting process");
        process();
        print("finishing process");

    } catch (IndexOutOfBoundsException e) {
        print("caught IOOBE");

    } catch (IOException e) {
        print("caught IOE");

    }
    print("finishing method");
}
  • In Java, Checked exceptions are subject to the Catch or Specify Requirement: code that might throw checked exceptions must be enclosed by either a try statement catching the exception or a method that specifies that it can throw the exception.
  • Java comes with a collection of built-in exception classes that you can use.
    • It is possible to create your own exception classes.

When to use Exceptions:

  • In general, use exceptions only for ‘unusual’ conditions. Use normal return statements to pass control to the caller for conditions that are ‘normal’.
  • Avoid using exceptions to control normal workflow.
This post is licensed under CC BY 4.0 by the author.