Java Object-Oriented Approach


Creative Commons License
This -Java Object-Oriented Approach- tutorial is licensed under a Creative Commons Attribution-NonCommercial 4.0 International License
Java SE 11 Developer certification (exam number 1Z0-819) here

Java Object-Oriented Approach

Headlines
Classes versus instances

Rule(s)

Example (reuse)

java.time.LocalDate first_of_January_1970 = java.time.LocalDate.EPOCH; // January 1, 1970
java.time.LocalDateTime now = java.time.LocalDateTime.now();

Example (user-defined class) Programmable thermostat app.

final class Program {
    Temperature _target_temperature;
    java.time.LocalDateTime _time;
}
             
public class Programmable_thermostat … {
    private Program[] _program = new Program[8]; // An attribute named '_program' as an array of 8 values, each having 'Program' as type
    …
Attributes (a.k.a. fields) and methods (a.k.a. functions or operations) are foundational content of classes

Rule(s)

Example (Smalltalk)

get_x
    "return of _x"
    ^_x.
set_x: x
    "assign _x with x"
    _x := x.

Rule(s)

Example

public class My_class {
    public float a; // To be avoided, absolutely!
    public final float b = 1963.F;
    private double _c;
    …
}
…
My_class mc = new My_class();
mc.a = 1.F; // OK because 'public'
// mc.b = 2.F; // Compilation error because 'final'
System.out.println(mc.b); // OK because 'public'
// mc._c = 3.; // Compilation error because 'private'
// System.out.println(mc._c); // Compilation error because 'private'

Rule(s)

Example

public class My_class {
    …
    private void _f() {…};
    public void g() {…}; // '_f' is probably called inside 'g' and/or in other methods…
}
…
My_class mc = new My_class();
// mc._f(); // Compilation error because 'private'
mc.g(); // OK because 'public'

Rule(s)

Example Covariance.Java.zip 

public class Family {
    java.util.Set<Individual> _members = new java.util.HashSet<>();
    …
    public void births(Individual... children) {
        for (Individual c : children) {
            _members.add(c);
        }
    }
    …
}
…
// Usage:
family.births(new Individual(6, 12, 1993), new Individual(15, 4, 1996), new Individual(22, 2, 2001));
// Alternative usage:
Individual kids[] = {new Individual(6, 12, 1993), new Individual(15, 4, 1996), new Individual(22, 2, 2001)};
family.births(kids);

Rule(s)

Class attributes and methods

Rule(s)

Example

public class Temperature {
    public static final float Min = -273.15F; // In Celsius
    …
    if(_value < Min) … // Or 'Temperature.Min' when one accesses this (public) attribute from outside the 'Temperature' class

Rule(s)

Example

// See inheritance section to understand why both 'final' are here used:
final public class Leap_year_UTILITY { 
    final public static boolean Leap_year(final java.util.Calendar date) {
        return ((date.get(java.util.Calendar.YEAR) % 4 == 0) && (date.get(java.util.Calendar.YEAR) % 100 != 0)) || (date.get(java.util.Calendar.YEAR) % 400 == 0);
    }
}

Static initialiser

Example

public class Control_center {
    final static Terminal[] _Terminals;
    …
    static { // This code is launched before any statement in the 'main' program:
        int number_of_terminals = …;
        _Terminals = new Terminal[number_of_terminals];
    }
    …
Visibility and encapsulation are illustrated by the iceberg metaphor. Hidden part is called “implementation” while visible part is called “interface”

Example

public class Individual {
    private java.time.LocalDate _birth_date; // Implementation is by definition hidden, i.e., 'private' here

    public static java.time.LocalDate Now() {
        return java.time.LocalDate.now();
    }

    public int age() { // Interface is by definition visible, i.e., 'public' here
        return Now().getYear() - _birth_date.getYear();
    }
    …

Variations on visibility

Rule(s)

Example Covariance.Java.zip 

public class Individual {
    java.time.LocalDate _birth_date; // "package" visibility
    …

public class Family { // The 'Individual.java' and 'Family.java' files must be in the same directory
    java.util.Set<Individual> _members = new java.util.HashSet<>();
    …
    public int last_child_birth_year() {
        int result = 0;
        for (Individual member : _members) {
            if (result < member._birth_date.getYear()) { // Access to '_birth_date' succeeds because 'Individual' and 'Family' are in the same package
                result = member._birth_date.getYear(); // Access to '_birth_date' succeeds because 'Individual' and 'Family' are in the same package
            }
        }
        return result;
    }
}

Rule(s)

Example

public class Prisoner {
    private String _file_number;
    public boolean equals(Object p) {
        if(p instanceof Prisoner) {
            return (this._file_number.equals(((Prisoner)p)._file_number)); // 'this' accesses to '_file_number' of 'p'; this is not really private!
        }
        return false;
    }
    …

Rule(s)

Example

//  This entire code is included in the 'My_class.java' file
class Class_with_package_visibility { // "package" visibility ('My_class' is probably a user class, but other classes in the same package may use it!)
…
}
public class My_class {
    private class Class_with_private_visibility { // 'private' visibility (such a declaration is allowed inside the user class only!)
        …
    }
    …
}
Naming space in Java relies on hierarchical directories of the Operating System (OS). Code access imposes location based on the import clause

Example

package my_code;
…
public class X { …

package my_code.my_extra_code; // Absolute path from 'classpath' OS variable
…
import my_code.X; // 'import my_code.*;' -> all is imported
…
public class Y extends X { … // 'X' has been previously imported

public class Y extends my_code.X { … // Alternative: no import, absolute path to 'X'

Rule(s)

Example

export classpath = $classpath:/usr/FranckBarbier

Package import using static

Example (without static import)

double cosinus = Math.cos(Math.PI); // Cosinus of 180 deg.

Rule(s)

Example

import static java.lang.Math.*; // 'cos', 'PI' and others… All static members…
…
double cosinus = cos(PI); // Shorter, instead of 'double cosinus = Math.cos(Math.PI);'
Constructor

Rule(s)

Example

public class Student {
    { // This code is executed before every constructor:
        System.out.println("Block initialiser of 'Student'");
    }
    public Student() { … // The no-argument constructor is re-introduced, cancelling the initial compiler's no-argument constructor
    public Student(String student_id) {
        this(); // Calling a constructor (the prior one) inside another!
        … // Additional stuff here…
    }
    …

Rule(s)

Inheritance

Rule(s)

Example of inheritance tree (in French)

Structural inheritance

Example Polymorphism.Java.zip 

abstract public class Compte_bancaire {
    private int _id;
    protected float _solde;
    protected float _cumul_interets;
    …
 
public class Compte_cheque extends Compte_bancaire {
    protected float _taux_interet;
    protected float _seuil;
    …

Behavioral inheritance

Example Polymorphism.Java.zip 

abstract public class Compte_bancaire {
    …
    public int id() { // This method is usable by 'Compte_cheque' objects!
        return _id;
    }
    …

Property extension

Example Polymorphism.Java.zip 

public class Compte_epargne_logement extends Compte_epargne {
    public final static float Taux_interet = Livret_A.Taux_interet * 2.F / 3.F; // Fixed rate in the French law
    public float taux_interet() {
        return Taux_interet;
    }
    …

Inheritance and constructors

Example Polymorphism.Java.zip 

abstract public class Compte_epargne extends Compte_bancaire {
    protected Compte_epargne(int id,float solde) {
        super(id,solde);
    }
}

Overriding (redefinition)

Example Polymorphism.Java.zip 

abstract public class Compte_bancaire {
    …
    abstract public float taux_interet(); // Abstract method
    public void appliquer_taux_interet() {
        _cumul_interets = _solde * (1.F + (taux_interet() / 100.F));
    }
}

public class Compte_cheque extends Compte_bancaire {
    …
    public float taux_interet() { // Abstract nature is removed when overriding
        return _taux_interet;
    }
    public void appliquer_taux_interet() { // Overriding as well
        if(_solde > _seuil) super.appliquer_taux_interet();
    }
}

Rule(s)

Example

// Assumption: 'Daughter' inherits from 'Mother', which inherits from 'Grandmother'. One wants in 'Daughter' to access to 'jewel' (not 'private') in 'Mother':
super.jewel;
// One now wants in 'Daughter' to access to 'other_jewel' (not 'private') in 'Grandmother':
// super.super.other_jewel; // Compilation error! Contrary to C++, Java prevents such an access

Rule(s)

Example

public class Note {
    private static int _Increment = 10;
    private final java.io.StringReader _source;
    public final static String Default_header = "Note: ";
    protected StringBuffer _text;

    private void initialization() { // 'private' prevents overriding -> to allow overriding, possibly use 'protected' instead
        _text = new StringBuffer(Default_header);
    }

    public Note(java.io.StringReader source) {
        _source = source;
        initialization(); // Polymorphism does not apply since it is indicated 'private' above
    }
…
public class Confidential_note extends Note {
    public final static String Default_header = "Confidential note: ";
    // private void initialization() { // Overriding does not work because 'private' in 'Note'
    //    _text = new StringBuffer(Default_header);
    // }

    public Confidential_note(java.io.StringReader source) {
        super(source);
    }
…
Note cn = new Confidential_note(new java.io.StringReader("Franck Barbier"));

final and inheritance

Rule(s)

Anonymous classes

Rule(s)

Example

public class Anonymous_class_test {
    public static void main(String[] args) {
        java.util.TimerTask timer_task = new java.util.TimerTask() {
            @Override
            public void run() {
                System.out.println("A behavior…");
            }
        };
        System.out.println(timer_task.getClass().getName()); // 'Anonymous_class_test$1' is displayed!
    …

Rule(s)

Double brace initialization

Rule(s)

Example

// Creation of an anonymous inner class, which extends 'java.util.HashSet':
java.util.Set<Mammutidae> presidents = new java.util.HashSet<>() {
    { // <- Block initialiser
        add(new Mammutidae("Macron"));
        add(new Mammutidae("Poutine"));
        add(new Mammutidae("Trump"));
    }
};
System.out.println(presidents.getClass().getName()); // 'Main$1' is displayed!
Polymorphism

Example Polymorphism.Java.zip 

Compte_cheque cc = new Compte_cheque(1963,10500.F,2.F,10000.F);
Compte_bancaire cb = cc; // 'cb' points to 'cc' since their mutual types are compatible through inheritance (see inheritance tree above)
cb.appliquer_taux_interet(); // 'appliquer_taux_interet' in 'Compte_cheque' is run since the runtime type of 'cb' is 'Compte_cheque'
cb = cel; // Assumption: 'cel' is a direct instance of 'Compte_epargne_logement'
cb.appliquer_taux_interet(); // Polymorphism again

Rule(s)

Example

// Assumption: 'Cat' directly or indirectly inherits from 'Animal':
Animal a = new Cat();
// Cat c = a; // Incompatible types: 'a' may point to an elephant, a mouse...
try {
    Cat c = (Cat) a;
} catch (ClassCastException cce) { // Runtime exception!
    System.err.println(cce.getMessage());
}

Covariance (on return types)

Rule(s)

Example Covariance.Java.zip 

public class Individual {
    java.time.LocalDate _birth_date;
    …
    public Individual cloning() { System.out.print("cloning in Individual...\n");
        return new Individual(_birth_date.getDayOfMonth(), _birth_date.getMonthValue(), _birth_date.getYear());
    }
}
…
public class Female extends Individual {
    …    
    @Override
    public Female cloning() { System.out.print("cloning in Female...\n");
        return new Female(_birth_date.getDayOfMonth(), _birth_date.getMonthValue(), _birth_date.getYear());
    }
}
…
public class Male extends Individual {
    …    
    @Override
    public Male cloning() { System.out.print("cloning in Male...\n");
        return new Male(_birth_date.getDayOfMonth(), _birth_date.getMonthValue(), _birth_date.getYear());
    }
}
…
Individual FranckBarbier = new Male(11, 1, 1963);
Individual clone = FranckBarbier.cloning(); // 'cloning in Male...' is displayed => covariance applies in Java!

Rule(s)

Example

class Individual
feature
    cloning : like Current is do Result := Current end;
    …
end

x,y : Female -- As direct descendant of 'Individual'
!!x -- Instantiation
y := x.cloning -- OK, 'cloning' returns a 'Female' object

Static method hiding using final

Example Final_and_static_methods.Java.zip 

public class My_class_mother {
    final static void My_method() {
        System.out.println("I'm both a 'final' and 'static' method in " + My_class_mother.class.getSimpleName() + ", what does it mean?");
    }
}

public class My_class extends My_class_mother {
    // 'static' methods can be 'hidden' instead of 'overridden', but 'final' in 'My_class_mother' prevents hidding here:
    //    static void My_method() { 
    //    }
    public static void main(String[] args) {
        My_class.My_method(); // Normal style, 'final' in 'My_class_mother' prevents any hidding in 'My_class'
        My_class mc = new My_class();
        mc.My_method(); // Weird Java style through instances!
    } 
}
Interfaces

Rule(s)

Example

public class Task implements java.util.Comparator<Task> {
    private int _priority;

    public Task(int priority) {
        _priority = priority;
    }

    @Override
    public int compare(Task t1, Task t2) {
        if (t1._priority < t2._priority) {
            return -1; // '-1' (or any negative) is a convention/contract imposed by 'java.util.Comparator<T>'
        }
        if (t1._priority == t2._priority) {
            return 0; // '0' is a convention/contract imposed by 'java.util.Comparator<T>'
        }
        return 1; // '1' (or any positive) is a convention/contract imposed by 'java.util.Comparator<T>'
    }
}

Interfaces: key issues

Rule(s)

Example

// Compilation error, attempt to (directly) instantiate an interface:
// Comparable<Integer> i = new Comparable<>();
// Instead, 'i' has for (design) type 'Comparable<Integer>' while it has 'Integer' as (runtime) compatible type:
Comparable<Integer> i = new Integer(0);

Rule(s)

Example Sort_illustration.Java.zip 

public class Sort_illustration<T extends Comparable<T>> {
    java.util.ArrayList<T> _representation;
    …
    void sort(int left, int right) {
        assert (left < right);
        for (int i = left; i < right; i++) {
            for (int j = i + 1; j <= right; j++) {
                _cost++;
                if (_representation.get(i).compareTo(_representation.get(j)) > 0) {
                    T temp = _representation.get(i);
                    _representation.set(i, _representation.get(j));
                    _representation.set(j, temp);
                }
            }
        }
    }  
    …  
}
…
public class Elephant implements Comparable<Elephant> {
    private float _weight;
    public int compareTo(Elephant e) {
        if(this._weight < e. _weight) return -1;
        …
    }
…
Sort_illustration<Elephant> elephant_zoo = new Sort_illustration<>(…); // 'elephant_zoo' is sortable

Multiple interface inheritance

Example

public interface I {
    String S = "S in I";
    void f();
}

public interface J {
    String S = "S in J";
    void f();
}

public interface K extends I, J { …

public class C implements K { …

Conflict about multiple interface inheritance

Example Multiple_inheritance.Java.zip 

public interface I {
    String S = "S in I";
    void f();
    void g(I i);
    I h();
}

public interface J {
    String S = "S in J";
    void f();
    void g(J j);
    J h();
}

public interface K extends I, J { … // Compilation error about 'h'

public class C implements K {
    public void f() { // Compilation error about 'g': 'g' from 'I' or 'g' from 'J'?
        g(this);
    }
    public void g(I i) {
    }
    public void g(J j) {
    }
    public static void main(String[] args) {
        System.out.println(I.S);
    }
}

interface changes from Java 8 and 9

Rule(s)

Example (with misconception on line 41) From_Java_9.Java.zip 

enum Size {
    S, M, L, XL, XXL
};

interface Proboscidea {
// From Java 8 (i.e., 'static' and 'default'):

    static String Reign() {
        return _French_name() + " in Animalia reign";
    }

    default String description() { // 'default' => 'public'
        return "Animal owning a trunk, whose size is " + trunk_size(); // Body is mandatory for default methods...
    }

    default boolean still_exists_() { // 'default' => 'public'
        return true; // Body is mandatory for default methods...
    }

    default String trunk_size() {
        return _trunk_size() == Size.S ? "small" : ""; // To be enhanced: test of values of 'Size' enumerated type
    }
// From Java 9 (i.e., 'private'):

    private static String _French_name() {
        return "Proboscidien";
    }

    private Size _trunk_size() { // 'private' methods *CANNOT* be used in descendants...
        return Size.S; // 'private' methods cannot be abstract...
    }
}

public class Mammutidae implements Proboscidea {

    @Override
    public boolean still_exists_() {
        return false; // Overriding occurs here...
    }

    private Size _trunk_size() { // Arrrgggglll... Overriding *FAILS*!
        return Size.XXL;
    }
}
Enumerated types (from Java 5)

Example (old-school style)

public static final byte Celsius = 0;
public static final byte Fahrenheit = 1;
public static final byte Kelvin = 2;
public Temperature(float value,byte unit) {…
…
Temperature t = new Temperature(18.F,3); // Error comes from the fact that '3' does not embody a meaningful value for temperature units!

Rule(s)

Example

public enum Temperature_unit {Celsius, Fahrenheit, Kelvin}
…
public Temperature(float value,Temperature_unit unit) { … // 'Temperature_unit' is simply used as a type
…
Temperature t = new Temperature(18.F,Temperature_unit.Celsius); // Later on, values of 'Temperature_unit' may be passed as arguments 
…
for(Temperature_unit unit : Temperature_unit.values()) System.out.print(“\t” + unit); // Java enumerated types have nice facilities like iterating

Rule(s)

Example Exception_management.Java.zip 

public enum Temperature_unit {
    Celsius("°C"), Fahrenheit("°F"), Kelvin("°K");

    final String _literal;
    private Temperature_unit(String literal) { _literal = literal; }
    public String toString() { return _literal; }
}
…
Temperature_unit tu = Temperature_unit.Celsius;
System.out.println(tu.toString()); // '°C' is displayed

Example

enum Decision_type {Conviction, Shortened_sentence, Final_discharge}
Enum<Decision_type> decision_type; // <=> 'Decision_type decision_type;'