Object-oriented programming basic details

Objectives

Constructors

Constructor examples

// Very basic class: class Date { private int month, day, year; // instance fields } // What Java adds to that code automatically: class Date extends Object { private int month, day, year; // instance fields Date() { super(); } } // Now let's add accessor and mutator methods and a second constructor class Date extends Object { private int month, day, year; // instance fields // Constructor - default public Date() { // Defaults to 2017-01-01 this(1, 1, 2017); // Calls other constructor } // Constructor public Date(int m, int d, int y) { super(); setMonth(m); setDay(d); setYear(y); } // Mutators public void setMonth(int m) { if (m < 1) month = 1; else if (m > 12) month = 12; else month = m; } public void setDay(int d) { // Note: Invalid dates are accepted: Feb. 31 if (d < 1) day = 1; else if (d > 31) day = 31; else day = d; } public void setYear(int y); // Note: Only years 1900 - 2199 are accepted if (y < 1900) year = 1900; else if (y >= 2200) year = 2199; else year = y; } // Accessors public int getMonth() { return month; } public int getDay() { return day; } public int getYear() { return year; } }

Accessors, mutators, and predicate methods

The "this" keyword

The this keyoword refers to the current object. It was used in the example above to call one constructor from another one in the same class. It is also used to differentiate instance variables from local variables when they have the same name. For example, here are the mutators from the previous example rewritten to work even when the local variable names are the same as the instance variable names.

// Mutators public void setMonth(int month) { if (month < 1) this.month = 1; else if (month > 12) this.month = 12; else this.month = month; } public void setDay(int d) { // Note: Invalid dates are accepted: Feb. 31 if (day < 1) this.day = 1; else if (day > 31) this.day = 31; else this.day = day; } public void setYear(int year); // Note: Only years 1900 - 2199 are accepted if (year < 1900) this.year = 1900; else if (year >= 2200) this.year = 2199; else this.year = year; }

Overloading

Multiple methods in a class can have the same name as long as the compiler can differentiate them by their signature, which means having a parameter list that differs by more than the parameter names (which are irrelevant in this case). The Date example above had overloaded constructors. Here's the same example with additional constructor overloading:

// Constructor - default constructor public Date() { // Defaults to 2017-01-01 this(1, 1, 2017); // Calls other constructor } // Constructor - copy constructor public Date(Date date) { // Sends copies of current object's data this(date.month, date.day, date.year); } // Constructor public Date(int m, int d, int y) { super(); setMonth(m); setDay(d); setYear(y); }

Overriding

Classes inherit the fields and methods (but not constructors) of the classes they extend (subclass). Sometimes the inherited methods do not do what you want them to. That is what overriding a method is for. You can write a new method that replaces the inherited method. One common example is the toString() method. It is a member of Object, so every class in Java has an inherited toString() instance method. It prints out something like this for the Date object: Date@1db9742. To make that more sensible, we can replace (override) the inherited method like this:

// @Override is called an annotation. It is not required, but it helps the compiler // recognize errors, so it is a safety feature. @Override public String toString() { // Returns date as String in format: yyyy-mm-dd return String.format("%4d-%02d-%02d", year, month, day); }

Composition

Composition simply means using objects as part of another object. Composition represents a has-a relationship in contrast to the is-a relationship that inheritance represents. The example below shows two four objects being used to compose a new object:

class Employee { public Date birthDate; public Date hireDate; public String firstName; public String lastName; }

Destructors

Static class members

Types of access

Stack vs. heap

Throwing an exception

Throwing an exception is easy. Use the keyword throw followed by the exception object you want to throw. If the exception is a checked exception, then the method the throw is contained in must either try and catch the exception or declare that it throws that type of exception in the method signature. For example:

public void setDate(int y, int m, int d) { // IllegalArgumentException is a runtime exception so a throws clause is // not needed in the method signature. int maxDay = 31; if (y < 1900 || y > 2199) throw new IllegalArgumentException("Year out of range"); if (m < 1 || m > 12) throw new IllegalArgumentException("Month out of range"); if (m == 4 || m == 6 || m == 9 || m == 11) { maxDay == 30; } else if (m == 2) { maxDay = 28; if (y % 4 == 0) maxDay = 29; if (y % 100 == 0) maxDay = 28; if (y % 400 == 0) maxDay = 29; } if (d < 1 || d > maxDay) throw new IllegalArgumentException("Day of month out of range"); year = y; month = m; day = d; }