Like a Family Tree, a ________ Shows the Inheritance Relationship Between Classes

Coffee Programming Tutorial

OOP - Composition, Inheritance & Polymorphism

At that place are two ways to reuse existing classes, namely, composition and inheritance. With composition (aka aggregation), you ascertain a new class, which is composed of existing classes. With inheritance, yous derive a new class based on an existing course, with modifications or extensions.

Limerick

We shall begin with reusing classes via composition - through examples.

Limerick EG. 1: The Author and Volume Classes

Let's start with the Writer class

OOP_AuthorClass.png

A class called Author is designed every bit shown in the form diagram. Information technology contains:

  • Three private fellow member variables: name (String), e-mail (String), and gender (char of either 'm' or 'f' - you might besides apply a boolean variable chosen isMale having value of true or false).
  • A constructor to initialize the name, email and gender with the given values.
    (There is no default constructor, equally there is no default value for proper name, email and gender.)
  • Public getters/setters: getName(), getEmail(), setEmail(), and getGender().
    (At that place are no setters for name and gender, as these properties are not designed to exist changed.)
  • A toString() method that returns " name (gender) at e-mail ", due east.g., "Tan Ah Teck (grand) at ahTeck@somewhere.com".
The Writer Class (Author.coffee)
i 2 iii four v 6 7 8 ix 10 xi 12 13 14 xv 16 17 18 xix 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
                    public class                  Author                  {        individual String name;    individual String email;    private char gender;             public Author(String name, String email, char gender) {       this.proper name = name;       this.email = email;       this.gender = gender;    }              public Cord getName() {       return proper name;    }        public char getGender() {       return gender;    }        public Cord getEmail() {       return email;    }        public void setEmail(String email) {       this.email = electronic mail;    }       */    public String toString() {       return name + " (" + gender + ") at " + email;    } }
A Test Driver for the Author Class (TestAuthor.java)
            public grade          TestAuthor          {    public static void chief(String[] args) {              Author ahTeck = new Author("Tan Ah Teck", "teck@nowhere.com", '1000');       System.out.println(ahTeck);                        ahTeck.setEmail("teck@somewhere.com");       Organization.out.println(ahTeck);                Organisation.out.println("name is: " + ahTeck.getName());              System.out.println("gender is: " + ahTeck.getGender());              System.out.println("email is: " + ahTeck.getEmail());           } }
A Book is written past one Author - Using an "Object" Fellow member Variable

OOP_BookClass.png

Let's design a Volume class. Assume that a book is written by 1 (and exactly one) author. The Volume class (equally shown in the class diagram) contains the following members:

  • Four individual member variables: name (String), author (an instance of the Author class nosotros accept merely created, assuming that each book has exactly ane author), price (double), and qty (int).
  • The public getters and setters: getName(), getAuthor(), getPrice(), setPrice(), getQty(), setQty().
  • A toString() that returns "'book-name' past author-name (gender) at email". Yous could reuse the Author's toString() method, which returns "writer-name (gender) at e-mail".
The Volume Grade (Book.coffee)
1 ii iii 4 v half dozen 7 8 9 x 11 12 13 14 15 xvi 17 eighteen 19 twenty 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
                    public class                  Volume                  {        private String name;    private Author author;    private double price;    individual int qty;          public Book(String name, Author writer, double price, int qty) {       this.proper noun = name;       this.author = writer;       this.toll = price;       this.qty = qty;    }              public String getName() {       render name;    }        public Author getAuthor() {       return author;      }        public double getPrice() {       return toll;    }        public void setPrice(double price) {       this.price = price;    }        public int getQty() {       return qty;    }        public void setQty(int qty) {       this.qty = qty;    }          public String toString() {       return "'" + proper noun + "' past " + author;      } }
A Test Commuter Programme for the Book Class (TestBook.java)
            public class          TestBook          {    public static void main(String[] args) {              Writer ahTeck = new Author("Tan Ah Teck", "ahTeck@somewhere.com", 'grand');       System.out.println(ahTeck);                        Book dummyBook = new Book("Java for dummies", ahTeck, 9.99, 99);       Organisation.out.println(dummyBook);                        dummyBook.setPrice(8.88);       dummyBook.setQty(88);       Organization.out.println("proper noun is: " + dummyBook.getName());              System.out.println("price is: " + dummyBook.getPrice());              System.out.println("qty is: " + dummyBook.getQty());              System.out.println("author is: " + dummyBook.getAuthor());                System.out.println("writer's proper name is: " + dummyBook.getAuthor().getName());              Arrangement.out.println("author's email is: " + dummyBook.getAuthor().getEmail());              Organisation.out.println("author'southward gender is: " + dummyBook.getAuthor().getGender());                      Book moreDummyBook = new Volume("Java for more dummies",             new Writer("Peter Lee", "peter@nowhere.com", 'm'),              19.99, 8);       Organization.out.println(moreDummyBook);             } }

Notes: In this example, I used "name" for Volume grade instead of "title" to illustrate that y'all tin can have a variable proper name in both the Author and Book classes, only they are distinct.

Composition EG. 2: The Point and Line Classes

class diagram

Equally an example of reusing a class via composition, suppose that nosotros have an existing class called Bespeak, defined as shown in the above class diagram. The source code is Here.

Suppose that we need a new grade called Line, nosotros tin can blueprint the Line class by re-using the Point form via composition. We say that "A line is equanimous of two points", or "A line has two points". Composition exhibits a "has-a" relationship.

OOP_CompositionLinePointDetails.png

UML Notation: In UML notations, composition is represented as a diamond-head line pointing to its constituents.

The Line Class via Composition (Line.coffee)
one two 3 four five half dozen vii 8 9 ten eleven 12 13 14 15 xvi 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 sixty 61 62 63 64 65 66 67 68 69 seventy 71 72 73 74 75 76 77 78 79 eighty 81
                    public class Line {       Point begin, end;           public Line(int x1, int y1, int x2, int y2) {       brainstorm = new Betoken(x1, y1);        end   = new Point(x2, y2);    }        public Line(Point begin, Point end) {       this.begin = brainstorm;         this.end   = stop;    }         public Point getBegin() {       return begin;    }    public Bespeak getEnd() {       return cease;    }    public void setBegin(Point brainstorm) {       this.begin = begin;    }    public void setEnd(Point stop) {       this.stop = end;    }      public int getBeginX() {       render begin.getX();      }    public void setBeginX(int x) {       begin.setX(x);      }    public int getBeginY() {       return begin.getY();      }    public void setBeginY(int y) {       begin.setY(y);      }    public int[] getBeginXY() {       return begin.getXY();      }    public void setBeginXY(int x, int y) {       brainstorm.setXY(x, y);      }    public int getEndX() {       return end.getX();      }    public void setEndX(int ten) {       end.setX(10);      }    public int getEndY() {       render end.getY();      }    public void setEndY(int y) {       end.setY(y);      }    public int[] getEndXY() {       return end.getXY();      }    public void setEndXY(int 10, int y) {       terminate.setXY(ten, y);      }          public String toString() {       return "Line[begin=" + begin + ",terminate=" + end + "]";                 }          public double getLength() {       return begin.altitude(finish);      } }
A Test Driver for Line Class (TestLine.java)
import java.util.Arrays;  public form          TestLine          {    public static void main(String[] args) {              Line l1 = new Line(ane, two, iii, 4);       Arrangement.out.println(l1);                Line l2 = new Line(new Point(5,six), new Point(7,8));         System.out.println(l2);                        l1.setBegin(new Signal(11, 12));       l1.setEnd(new Point(xiii, 14));       Organization.out.println(l1);                Arrangement.out.println("begin is: " + l1.getBegin());                Organization.out.println("end is: " + l1.getEnd());                 l1.setBeginX(21);       l1.setBeginY(22);       l1.setEndX(23);       l1.setEndY(24);       Organization.out.println(l1);                System.out.println("begin's x is: " + l1.getBeginX());              System.out.println("begin'southward y is: " + l1.getBeginY());              System.out.println("end'south 10 is: " + l1.getEndX());              System.out.println("end'due south y is: " + l1.getEndY());               l1.setBeginXY(31, 32);       l1.setEndXY(33, 34);       System.out.println(l1);                Organisation.out.println("begin's x and y are: " + Arrays.toString(l1.getBeginXY()));              System.out.println("cease's x and y are: " + Arrays.toString(l1.getEndXY()));                      Organisation.out.printf("length is: %.2f%n", l1.getLength());           } }

Exercise: Try writing these more than complex methods for the Line class:

            public double getGradient()   public double distance(int ten, int y) public double distance(Bespeak p)   public boolen intersects(Line another)

Composition EG. iii: The Point and Circle Classes

Suppose that nosotros take an existing class called Point, defined equally shown in the class diagram. The source code is HERE.

OOP_MyPoint.png

A grade called Circle is designed every bit shown in the course diagram.

ClassDiagram_CirclePoint.png

Information technology contains:

  • 2 private member variables: a radius (double) and a heart (an instance of Point form, which we created earlier).
  • The constructors, public getters and setters.
  • Methods getCenterX(), setCenterX(), getCenterY(), setCenterY(), getCenterXY(), setCenterXY(), etc.
  • A toString() method that returns a string clarification of this instance in the format of "Circle[center=(x,y),radius=r]". You lot should re-utilize the Indicate's toString() to print "(ten,y)".
  • A altitude(Circumvolve another) method that returns the distance from the center of this instance to the heart of the given Circle instance (chosen another).
The Circle grade (Circle.java)
i 2 3 iv 5 half dozen vii 8 nine x 11 12 13 14 15 16 17 18 nineteen xx 21 22 23 24 25 26 27 28 29 xxx 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 fifty 51 52 53 54 55 56 57 58 59 sixty 61 62 63 64 65 66 67 68 69 seventy 71 72 73 74 75 76 77 78 79 80
                    public class                  Circle                  {       private Point heart;      private double radius;             public Circle() {       this.center = new Indicate();       this.radius = one.0;    }        public Circumvolve(int xCenter, int yCenter, double radius) {       centre = new Point(xCenter, yCenter);       this.radius = radius;    }        public Circle(Point center, double radius) {       this.centre = center;         this.radius = radius;    }         public double getRadius() {       return this.radius;    }    public void setRadius(double radius) {       this.radius = radius;    }    public Point getCenter() {       return this.heart;      }    public void setCenter(Bespeak middle) {       this.heart = heart;    }      public int getCenterX() {       return center.getX();      }    public void setCenterX(int x) {       center.setX(10);      }    public int getCenterY() {       render eye.getY();      }    public void setCenterY(int y) {       center.setY(y);      }    public int[] getCenterXY() {       return center.getXY();      }    public void setCenterXY(int x, int y) {       center.setXY(x, y);      }          public String toString() {       return "Circumvolve[center=" + center + ",radius=" + radius + "]";      }          public double getArea() {       return Math.PI * radius * radius;    }          public double getCircumference() {       render 2.0 * Math.PI * radius;    }          public double distance(Circle another) {       render center.altitude(another.center);     }  }
A Exam Driver for the Circumvolve Class (TestCircle.coffee)
ane 2 iii iv v 6 7 viii 9 10 11 12 13 14 15 16 17 xviii 19 twenty 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
                    public class                  TestCircle                  {    public static void main(Cord[] args) {              Circle c1 = new Circle();       System.out.println(c1);         Circle c2 = new Circle(one, two, 3.3);       System.out.println(c2);         Circumvolve c3 = new Circle(new Betoken(four, 5), vi.6);          System.out.println(c3);                 c1.setCenter(new Point(11, 12));       c1.setRadius(13.three);       System.out.println(c1);         System.out.println("center is: " + c1.getCenter());         Organization.out.println("radius is: " + c1.getRadius());        c1.setCenterX(21);       c1.setCenterY(22);       System.out.println(c1);         Arrangement.out.println("center's x is: " + c1.getCenterX());       System.out.println("center'southward y is: " + c1.getCenterY());       c1.setCenterXY(31, 32);       System.out.println(c1);         System.out.println("center's x is: " + c1.getCenterXY()[0]);       System.out.println("center's y is: " + c1.getCenterXY()[1]);               System.out.printf("area is: %.2f%n", c1.getArea());       System.out.printf("circumference is: %.2f%north", c1.getCircumference());               System.out.printf("altitude is: %.2f%n", c1.distance(c2));       System.out.printf("altitude is: %.2f%n", c2.altitude(c1));    } }

Exercises

LINK TO EXERCISES

Inheritance

In OOP, we often organize classes in hierarchy to avoid duplication and reduce redundancy. The classes in the lower hierarchy inherit all the variables (static attributes) and methods (dynamic behaviors) from the higher hierarchies. A class in the lower hierarchy is called a subclass (or derived, child, extended class). A class in the upper hierarchy is chosen a superclass (or base, parent class). Past pulling out all the mutual variables and methods into the superclasses, and get out the specialized variables and methods in the subclasses, redundancy tin be profoundly reduced or eliminated equally these common variables and methods do not demand to be repeated in all the subclasses. For example,

OOP_InheritanceExamples.png

A subclass inherits all the variables and methods from its superclasses, including its firsthand parent as well as all the ancestors. It is important to note that a bracket is not a "subset" of a superclass. In contrast, subclass is a "superset" of a superclass. It is because a bracket inherits all the variables and methods of the superclass; in addition, information technology extends the superclass by providing more variables and methods.

In Java, you define a subclass using the keyword "extends", due east.g.,

class Goalkeeper          extends          SoccerPlayer {......} grade MyApplet          extends          java.applet.Applet {.....} class Cylinder          extends          Circle {......}        

OOP_UMLSuperSubClass.png

UML Notation: The UML note for inheritance is a solid line with a hollow arrowhead leading from the subclass to its superclass. By convention, superclass is fatigued on tiptop of its subclasses as shown.

Inheritance EG. 1: The Circle and Cylinder Classes

OOP_CircleCylinder.png

In this example, nosotros derive a subclass called Cylinder from the superclass Circle, which nosotros have created in the previous affiliate. It is of import to annotation that we reuse the class Circle. Reusability is one of the most important properties of OOP. (Why reinvent the wheels?) The class Cylinder inherits all the member variables (radius and color) and methods (getRadius(), getArea(), amidst others) from its superclass Circle. It farther defines a variable chosen pinnacle, ii public methods - getHeight() and getVolume() and its own constructors, as shown:

Circle.java (Re-produced)
public course          Circle          {        private double radius;    private String colour;         public Circle() {       this.radius = 1.0;       this.color = "ruby-red";       System.out.println("Construced a Circumvolve with Circle()");      }    public Circle(double radius) {       this.radius = radius;       this.color = "cherry-red";       System.out.println("Construced a Circle with Circle(radius)");      }    public Circle(double radius, Cord color) {       this.radius = radius;       this.color = color;       System.out.println("Construced a Circle with Circle(radius, color)");      }         public double getRadius() {       render this.radius;    }    public String getColor() {       return this.color;    }    public void setRadius(double radius) {       this.radius = radius;    }    public void setColor(Cord color) {       this.colour = colour;    }         public String toString() {       return "Circumvolve[radius=" + radius + ",colour=" + color + "]";    }         public double getArea() {       render radius * radius * Math.PI;    } }
Cylinder.java
            public class          Cylinder extends Circle          {        private double tiptop;         public Cylinder() {       super();         this.height = ane.0;       System.out.println("Synthetic a Cylinder with Cylinder()");      }    public Cylinder(double top) {       super();         this.top = height;       System.out.println("Constructed a Cylinder with Cylinder(height)");      }    public Cylinder(double height, double radius) {       super(radius);         this.height = height;       Organisation.out.println("Synthetic a Cylinder with Cylinder(height, radius)");      }    public Cylinder(double height, double radius, String color) {       super(radius, color);         this.elevation = height;       System.out.println("Constructed a Cylinder with Cylinder(tiptop, radius, color)");      }         public double getHeight() {       return this.summit;    }    public void setHeight(double top) {       this.pinnacle = height;    }         public String toString() {       return "This is a Cylinder";      } }
A Test Drive for the Cylinder Class (TestCylinder.java)
            public class          TestCylinder          {    public static void main(String[] args) {       Cylinder cy1 = new Cylinder();                     System.out.println("Radius is " + cy1.getRadius()          + ", Peak is " + cy1.getHeight()          + ", Color is " + cy1.getColor()          + ", Base area is " + cy1.getArea()          + ", Volume is " + cy1.getVolume());                      Cylinder cy2 = new Cylinder(5.0, ii.0);                     Organization.out.println("Radius is " + cy2.getRadius()          + ", Acme is " + cy2.getHeight()          + ", Color is " + cy2.getColor()          + ", Base area is " + cy2.getArea()          + ", Volume is " + cy2.getVolume());                  } }

Keep the "Cylinder.coffee" and "TestCylinder.coffee" in the aforementioned directory as "Circle.class" (because we are reusing the class Circle). Compile and run the program.

Method Overriding & Variable Hiding

A subclass inherits all the member variables and methods from its superclasses (the firsthand parent and all its ancestors). It can utilize the inherited methods and variables as they are. It may also override an inherited method by providing its own version, or hide an inherited variable past defining a variable of the aforementioned proper name.

For example, the inherited method getArea() in a Cylinder object computes the base area of the cylinder. Suppose that nosotros decide to override the getArea() to compute the surface area of the cylinder in the bracket Cylinder. Below are the changes:

1 2 iii iv v half-dozen 7 8 nine x eleven 12 13 14 15 16 17
public class                  Cylinder extends Circle                  {    ......        @Override                  public double getArea() {       return 2*Math.PI*getRadius()*peak + two*super.getArea();    }                      public double getVolume() {       return                  super.getArea()*height;       }                      @Override    public String toString() {       render "Cylinder[" + super.toString() + ",height=" + meridian + "]";       }                  }

If getArea() is called from a Circle object, it computes the area of the circle. If getArea() is called from a Cylinder object, it computes the surface area of the cylinder using the overridden implementation. Annotation that you take to use public accessor method getRadius() to retrieve the radius of the Circumvolve, because radius is declared individual and therefore not attainable to other classes, including the bracket Cylinder.

Only if you override the getArea() in the Cylinder, the getVolume() (=getArea()*height) no longer works. Information technology is because the overridden getArea() will be used in Cylinder, which does not compute the base of operations area. You can fix this problem by using super.getArea() to utilise the superclass' version of getArea(). Annotation that super.getArea() tin can only be issued from the subclass definition, but no from an instance created, e.g. c1.super.getArea(), every bit it suspension the information hiding and encapsulation principle.

Annotation @Override (JDK 1.5)

The "@Override" is known every bit notation (introduced in JDK i.five), which asks compiler to bank check whether at that place is such a method in the superclass to be overridden. This helps greatly if yous misspell the name of the method to be overridden. For instance, suppose that you wish to override method toString() in a subclass. If @Override is not used and toString() is misspelled as TOString(), it volition be treated as a new method in the subclass, instead of overriding the superclass. If @Override is used, the compiler will point an mistake.

@Override annotation is optional, but certainly dainty to accept.

Annotations are not programming constructs. They have no outcome on the programme output. Information technology is only used by the compiler, discarded after compilation, and not used by the runtime.

Keyword "super"

Recall that inside a class definition, yous tin use the keyword this to refer to this instance. Similarly, the keyword super refers to the superclass, which could be the firsthand parent or its ancestor.

The keyword super allows the subclass to access superclass' methods and variables within the bracket' definition. For example, super() and super(argumentList) can be used invoke the superclass' constructor. If the subclass overrides a method inherited from its superclass, says getArea(), you can use super.getArea() to invoke the superclass' version within the subclass definition. Similarly, if your subclass hides i of the superclass' variable, you can use super.variableName to refer to the subconscious variable within the subclass definition.

More on Constructors

Recall that the subclass inherits all the variables and methods from its superclasses. Withal, the subclass does non inherit the constructors of its superclasses. Each form in Java defines its own constructors.

In the body of a constructor, y'all tin can use super(args) to invoke a constructor of its firsthand superclass. Notation that super(args), if it is used, must exist the commencement statement in the bracket' constructor. If it is non used in the constructor, Java compiler automatically insert a super() statement to invoke the no-arg constructor of its immediate superclass. This follows the fact that the parent must be built-in before the child can be born. You demand to properly construct the superclasses earlier yous can construct the bracket.

Default no-arg Constructor

If no constructor is defined in a class, Java compiler automatically create a no-argument (no-arg) constructor, that simply bug a super() call, equally follows:

            public          ClassName          () {      super();    }

Take note that:

  • The default no-arg constructor will non be automatically generated, if one (or more) constructor was defined. In other words, you need to ascertain no-arg constructor explicitly if other constructors were divers.
  • If the firsthand superclass does not take the default constructor (it defines some constructors but does non define a no-arg constructor), you will get a compilation fault in doing a super() call. Annotation that Java compiler inserts a super() equally the first statement in a constructor if in that location is no super(args).

Unmarried Inheritance

Java does not support multiple inheritance (C++ does). Multiple inheritance permits a subclass to have more than one straight superclasses. This has a serious drawback if the superclasses have conflicting implementation for the same method. In Java, each bracket tin can have 1 and only one straight superclass, i.e., unmarried inheritance. On the other manus, a superclass can take many subclasses.

Common Root Class - java.lang.Object

Java adopts a so-called common-root arroyo. All Java classes are derived from a common root grade called coffee.lang.Object. This Object form defines and implements the common behaviors that are required of all the Java objects running nether the JRE. These common behaviors enable the implementation of features such as multi-threading and garbage collector.

Inheritance EG. ii: The Point2D and Point3D Classes

OOP_PointPoint3D.png

The Superclass Point2D.java
            public class          Point2D          {        individual int 10, y;             public Point2D() {         this.x = 0;       this.y = 0;    }        public Point2D(int x, int y) {       this.x = x;       this.y = y;    }         public int getX() {       return this.10;    }    public void setX(int x) {       this.x = x;    }    public int getY() {       return this.y;    }    public void setY(int y) {       this.y = y;    }         @Override    public Cord toString() {       render "(" + this.x + "," + this.y + ")";    } }
The Subclass Point3D.coffee
one 2 3 4 5 half-dozen 7 eight 9 10 11 12 13 14 15 16 17 18 19 twenty 21 22 23 24 25 26 27 28 29 30 31 32 33 34
                    public class                  Point3D extends Point2D                  {        private int z;             public Point3D() {         super();            this.z = 0;    }        public Point3D(int x, int y, int z) {       super(x, y);       this.z = z;    }         public int getZ() {       render this.z;    }    public void setZ(int z) {       this.z = z;    }         @Override    public String toString() {       return "(" + super.getX() + "," + super.getY() + "," + this.z + ")";    } }
A Test Driver for Point2D and Point3D Classes (TestPoint2DPoint3D.java)
1 ii iii four five 6 7 8 9 10 eleven 12 thirteen 14 xv xvi 17 eighteen 19 20 21 22 23 24 25 26 27 28 29 xxx 31 32 33 34
                    public class                  TestPoint2DPoint3D                  {    public static void main(String[] args) {                     Point2D p2a = new Point2D(i, 2);       System.out.println(p2a);         Point2D p2b = new Point2D();         System.out.println(p2b);              p2a.setX(3);         p2a.setY(4);       System.out.println(p2a);         Organization.out.println("10 is: " + p2a.getX());       Organization.out.println("ten is: " + p2a.getY());                      Point3D p3a = new Point3D(xi, 12, 13);       System.out.println(p3a);         Point2D p3b = new Point3D();         System.out.println(p3b);              p3a.setX(21);         p3a.setY(22);         p3a.setZ(23);         System.out.println(p3a);         System.out.println("10 is: " + p3a.getX());         System.out.println("y is: " + p3a.getY());         Organization.out.println("z is: " + p3a.getZ());      } }

Inheritance EG. 3: Superclass Person and its Subclasses

OOP_PersonStudnetTeacher.png

Suppose that we are required to model students and teachers in our application. We can ascertain a superclass called Person to store common backdrop such every bit name and address, and subclasses Educatee and Teacher for their specific properties. For students, we need to maintain the courses taken and their respective grades; add a course with grade, impress all courses taken and the average form. Assume that a student takes no more thirty courses for the entire program. For teachers, we need to maintain the courses taught currently, and able to add or remove a course taught. Assume that a teacher teaches not more than than five courses concurrently.

We design the classes every bit follows.

The Superclass Person.java
            public course          Person          {        private String proper name, address;            public Person(String proper name, String address) {       this.name = name;       this.address = address;    }                public String getName() {       return name;    }        public String getAddress() {       return accost;    }        public void setAddress(String accost) {       this.address = address;    }            @Override    public String toString() {       return name + "(" + address + ")";    } }
The Subclass Pupil.coffee
            public class          Student extends Person          {        private int numCourses;       individual String[] courses;     individual int[] grades;         individual static concluding int MAX_COURSES = 30;             public Student(String proper name, String accost) {       super(proper name, accost);       numCourses = 0;       courses = new String[MAX_COURSES];       grades = new int[MAX_COURSES];    }            @Override    public String toString() {       return "Student: " + super.toString();    }            public void addCourseGrade(Cord class, int grade) {       courses[numCourses] = course;       grades[numCourses] = form;       ++numCourses;    }            public void printGrades() {       System.out.impress(this);       for (int i = 0; i < numCourses; ++i) {          Organisation.out.print(" " + courses[i] + ":" + grades[i]);       }       System.out.println();    }            public double getAverageGrade() {       int sum = 0;       for (int i = 0; i < numCourses; i++ ) {          sum += grades[i];       }       return (double)sum/numCourses;    } }
The Subclass Teacher.java
            public class          Teacher extends Person          {        private int numCourses;       private String[] courses;     individual static last int MAX_COURSES = five;             public Teacher(String name, String address) {       super(name, accost);       numCourses = 0;       courses = new String[MAX_COURSES];    }            @Override    public String toString() {       return "Teacher: " + super.toString();    }            public boolean addCourse(String form) {              for (int i = 0; i < numCourses; i++) {          if (courses[i].equals(course)) return false;       }       courses[numCourses] = grade;       numCourses++;       return truthful;    }            public boolean removeCourse(String form) {       boolean found = false;              int courseIndex = -i;         for (int i = 0; i < numCourses; i++) {          if (courses[i].equals(course)) {             courseIndex = i;             found = true;             pause;          }       }       if (found) {                    for (int i = courseIndex; i < numCourses-1; i++) {             courses[i] = courses[i+1];          }          numCourses--;          return truthful;       } else {          render simulated;       }    } }
A Test Driver (TestPerson.java)
            public class          TestPerson          {    public static void main(Cord[] args) {              Student s1 = new Student("Tan Ah Teck", "1 Happy Ave");       s1.addCourseGrade("IM101", 97);       s1.addCourseGrade("IM102", 68);       s1.printGrades();              Organisation.out.println("Average is " + s1.getAverageGrade());                      Teacher t1 = new Teacher("Paul Tan", "8 dusk way");       System.out.println(t1);              Cord[] courses = {"IM101", "IM102", "IM101"};       for (String course: courses) {          if (t1.addCourse(grade)) {             System.out.println(class + " added");          } else {             Arrangement.out.println(course + " cannot be added");          }       }                            for (String course: courses) {          if (t1.removeCourse(course)) {             Organisation.out.println(course + " removed");          } else {             Organisation.out.println(course + " cannot exist removed");          }       }                         } }

Exercises

LINK TO EXERCISES

Composition vs. Inheritance

"A line is composed of 2 points" vs. "A line is a point extended by some other bespeak"

Think that there are two means of reusing existing classes: composition and inheritance. We accept seen that a Line class can be implemented using composition of Signal course - "A line is composed of 2 points", in the previous section.

A Line can also be implemented, using inheritance from the Indicate class - "A line is a bespeak extended by another point". Let's phone call this bracket LineSub (to differentiate from the Line class using composition).

OOP_PointLineSub.png

The Superclass Point.java

As above.

The Subclass LineSub.java
1 2 3 4 5 6 seven 8 9 10 11 12 13 14 15 16 17 xviii nineteen 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 xl 41 42 43 44 45 46 47 48 49 l 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 lxx 71 72 73 74 75 76 77 78 79 lxxx 81 82
                    public form                  LineSub extends Point                  {        Point end;           public LineSub(int x1, int y1, int x2, int y2) {       super(x1, y1);       this.end = new Point(x2, y2);      }        public LineSub(Point begin, Point finish) {       super(begin.getX(), begin.getY());         this.finish = cease;    }          public Point getBegin() {       return this;      }    public Betoken getEnd() {       return terminate;    }    public void setBegin(Point begin) {       super.setX(begin.getX());       super.setY(begin.getY());    }    public void setEnd(Point end) {       this.stop = terminate;    }          public int getBeginX() {       return super.getX();     }    public void setBeginX(int x) {       super.setX(x);           }    public int getBeginY() {       return super.getY();    }    public void setBeginY(int y) {       super.setY(y);    }    public int[] getBeginXY() {       render super.getXY();    }    public void setBeginXY(int ten, int y) {       super.setXY(x, y);    }    public int getEndX() {       return cease.getX();    }    public void setEndX(int x) {       stop.setX(x);    }    public int getEndY() {       return finish.getY();    }    public void setEndY(int y) {       stop.setY(y);    }    public int[] getEndXY() {       return terminate.getXY();    }    public void setEndXY(int x, int y) {       end.setXY(x, y);    }          public String toString() {       return "LineSub[begin=" + super.toString() + ",end=" + end + "]";    }          public double getLength() {       return super.distance(end);    } }
A Exam Driver (TestLineSub.coffee)
i 2 iii 4 5 6 7 8 9 10 11 12 13 14 xv sixteen 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
                    public class                  TestLineSub                  {    public static void main(String[] args) {              LineSub l1 = new LineSub(ane, 2, 3, four);       System.out.println(l1);         LineSub l2 = new LineSub(new Point(five,half-dozen), new Indicate(7,eight));       Organization.out.println(l2);               l1.setBegin(new Betoken(11, 12));       l1.setEnd(new Point(xiii, xiv));       System.out.println(l1);         Organisation.out.println("begin is: " + l1.getBegin());       System.out.println("finish is: " + l1.getEnd());        l1.setBeginX(21);       l1.setBeginY(22);       l1.setEndX(23);       l1.setEndY(24);       System.out.println(l1);       Arrangement.out.println(l1);         Organization.out.println("brainstorm's ten is: " + l1.getBeginX());       Arrangement.out.println("begin's y is: " + l1.getBeginY());       Organisation.out.println("end's x is: " + l1.getEndX());       System.out.println("end'due south y is: " + l1.getEndY());        l1.setBeginXY(31, 32);       l1.setEndXY(33, 34);       Arrangement.out.println(l1);         System.out.println("begin's x is: " + l1.getBeginXY()[0]);       System.out.println("begin'south y is: " + l1.getBeginXY()[1]);       System.out.println("end'southward x is: " + l1.getEndXY()[0]);       System.out.println("end's y is: " + l1.getEndXY()[ane]);               System.out.printf("length is: %.2f%n", l1.getLength());    } }

Notes: This is the same test commuter used in the earlier example on composition, except change in classname.

Study both versions of the Line class (Line and LineSub). I suppose that it is easier to say that "A line is composed of two points" than that "A line is a point extended by another bespeak".

Dominion of Thumb: Use limerick if possible, before because inheritance. Use inheritance only if in that location is a clear hierarchical relationship between classes.

Exercises

LINK TO EXERCISES ON Composition VS INHERITANCE

Polymorphism

The word "polymorphism" means "many forms". It comes from Greek word "poly" (means many) and "morphos" (means grade). For examples, in chemistry, carbon exhibits polymorphism because it tin can exist found in more than than one class: graphite and diamond. But, each of the form has it own distinct properties (and price).

Substitutability

A bracket possesses all the attributes and operations of its superclass (because a subclass inherited all attributes and operations from its superclass). This means that a bracket object can exercise whatsoever its superclass can do. As a result, nosotros can substitute a subclass instance when a superclass case is expected, and everything shall work fine. This is called substitutability.

OOP_PolymorphismCircleCylinder.png

In our before example of Circumvolve and Cylinder: Cylinder is a bracket of Circle. We tin can say that Cylinder "is-a" Circle (really, it "is-more-than-a" Circle). Subclass-superclass exhibits a so called "is-a" relationship.

Circle.java
            public form Circle {        private double radius;        public Circle(double radius) {       this.radius = radius;    }        public double getRadius() {       return this.radius;    }        public double getArea() {       render radius * radius * Math.PI;    }        public Cord toString() {       return "Circumvolve[radius=" + radius + "]";    } }
Cylinder.java
            public class          Cylinder extends Circle          {        private double height;        public Cylinder(double pinnacle, double radius) {       super(radius);       this.height = elevation;    }        public double getHeight() {       return this.acme;    }        public double getVolumne() {       return super.getArea() * top;    }        @Override    public double getArea() {       return ii.0 * Math.PI * getRadius() * pinnacle;    }        @Override    public Cord toString() {       return "Cylinder[height=" + height + "," + super.toString() + "]";    } }

Via substitutability, we tin create an case of Cylinder, and assign information technology to a Circle (its superclass) reference, as follows:

            Circle          c1 = new          Cylinder(i.1, 2.2);

Yous can invoke all the methods defined in the Circle grade for the reference c1, (which is actually property a Cylinder object), e.1000.

            Organization.out.println(c1.getRadius());        

This is because a subclass instance possesses all the properties of its superclass.

Even so, you CANNOT invoke methods divers in the Cylinder class for the reference c1, e.g.

            c1.getHeight();          //compilation error: cannot notice symbol method getHeight()          c1.getVolume();          //compilation error: cannot find symbol method getVolume()        

This is because c1 is a reference to the Circumvolve class, which does not know virtually methods defined in the subclass Cylinder.

c1 is a reference to the Circumvolve class, but holds an object of its subclass Cylinder. The reference c1, however, retains its internal identity. In our example, the subclass Cylinder overrides methods getArea() and toString(). c1.getArea() or c1.toString() invokes the overridden version defined in the subclass Cylinder, instead of the version defined in Circle. This is because c1 is in fact belongings a Cylinder object internally.

Organization.out.println(c1.toString());            Cylinder[height=1.1,Circle[radius=2.2]]          Organisation.out.println(c1.getArea());           
Summary
  1. A subclass example can be assigned (substituted) to a superclass' reference.
  2. Once substituted, we can invoke methods defined in the superclass; we cannot invoke methods defined in the subclass.
  3. However, if the subclass overrides inherited methods from the superclass, the subclass (overridden) versions will be invoked.

Polymorphism EG. 1: Shape and its Subclasses

Polymorphism is very powerful in OOP to separate the interface and implementation and then equally to allow the developer to plan at the interface in the pattern of a circuitous organization.

Consider the post-obit example. Suppose that our program uses many kinds of shapes, such as triangle, rectangle so on. Nosotros should blueprint a superclass called Shape, which defines the public interfaces (or behaviors) of all the shapes. For example, we would like all the shapes to accept a method called getArea(), which returns the area of that particular shape. The Shape course can be written as follow.

OOP_PolymorphismShape.png

Superclass Shape.java
            public class          Shape          {        private String color;            public Shape (String color) {       this.color = color;    }            @Override    public String toString() {       render "Shape[color=" + color + "]";    }            public double getArea() {              Organisation.err.println("Shape unknown! Cannot compute area!");       return 0;    } }

Take note that we have a problem writing the getArea() method in the Shape class, considering the area cannot be computed unless the actual shape is known. Nosotros shall print an error bulletin for the fourth dimension being. In the later department, I shall show you how to resolve this trouble.

Nosotros can so derive subclasses, such every bit Triangle and Rectangle, from the superclass Shape.

Subclass Rectangle.coffee
            public class          Rectangle extends Shape          {        private int length, width;            public Rectangle(String colour, int length, int width) {       super(colour);       this.length = length;       this.width = width;    }            @Override    public String toString() {       return "Rectangle[length=" + length + ",width=" + width + "," + super.toString() + "]";    }            @Override    public double getArea() {       return length*width;    } }
Subclass Triangle.java
            public class          Triangle extends Shape          {        private int base, height;            public Triangle(Cord color, int base, int height) {       super(colour);       this.base of operations = base;       this.height = height;    }            @Override    public String toString() {       return "Triangle[base=" + base + ",meridian=" + height + "," + super.toString() + "]";    }            @Override    public double getArea() {       render 0.5*base of operations*summit;    } }

The subclasses override the getArea() method inherited from the superclass, and provide the proper implementations for getArea().

A Test Driver (TestShape.java)

In our application, we could create references of Shape, and assigned them instances of subclasses, equally follows:

            public course          TestShape          {    public static void main(String[] args) {          Shape          s1 = new          Rectangle("red", four, 5);         System.out.println(s1);            Rectangle[length=4,width=5,Shape[color=red]]          Organization.out.println("Area is " + s1.getArea());                 Shape s2 = new Triangle("blue", 4, 5);         System.out.println(s2);            Triangle[base of operations=4,height=5,Shape[color=blue]]          System.out.println("Area is " + s2.getArea());             } }

The beauty of this code is that all the references are from the superclass (i.e., programming at the interface level). Yous could instantiate different subclass instance, and the code withal works. You could extend your programme easily past adding in more subclasses, such as Circumvolve, Square, etc, with ease.

Nonetheless, the above definition of Shape class poses a problem, if someone instantiate a Shape object and invoke the getArea() from the Shape object, the program breaks.

public course          TestShape          {    public static void chief(String[] args) {              Shape s3 = new Shape("green");       System.out.println(s3);              Organization.out.println("Expanse is " + s3.getArea());             } }

This is because the Shape class is meant to provide a mutual interface to all its subclasses, which are supposed to provide the actual implementation. We practice not want anyone to instantiate a Shape case. This problem can exist resolved past using the then-called abstract course.

Polymorphism EG. 2: Monster and its Subclasses

OOP_PolymorphismMonster.png

Polymorphism is a powerful machinery in OOP to divide the interface and implementation so equally to permit the programmer to program at the interface in the design of a circuitous system. For example, in our game app, we take many types of monsters that can set on. We shall pattern a superclass called Monster and define the method assault() in the superclass. The subclasses shall and then provides their actual implementation. In the chief program, nosotros declare instances of superclass, substituted with actual subclass; and invoke method defined in the superclass.

Superclass Monster.java
            public form          Monster          {        private Cord name;         public Monster(String name) {       this.name = name;    }         public String attack() {       return "!^_&^$@+%$* I don't know how to set on!";           } }
Bracket FireMonster.java
public class          FireMonster extends Monster          {        public FireMonster(Cord name) {       super(name);    }        @Override    public String attack() {       return "Assail with fire!";     } }
Subclass WaterMonster.coffee
public class          WaterMonster extends Monster          {        public WaterMonster(String name) {       super(proper name);    }        @Override    public String attack() {       return "Attack with h2o!";    } }
Subclass StoneMonster.java
public class          StoneMonster extends Monster          {        public StoneMonster(String proper name) {       super(name);    }        @Override    public Cord set on() {       return "Attack with stones!";    } }
A Test Commuter TestMonster.java
public class TestMonster {    public static void main(String[] args) {                        Monster          m1 = new          FireMonster("r2u2");             Monster          m2 = new          WaterMonster("u2r2");            Monster          m3 = new          StoneMonster("r2r2");                 System.out.println(m1.assail());                System.out.println(m2.attack());                System.out.println(m3.assail());                        m1 = new StoneMonster("a2b2");         Arrangement.out.println(m1.attack());                           Monster          m4 = new          Monster("u2u2");       System.out.println(m4.set on());             } }

Upcasting & Downcasting

Upcasting a Subclass Instance to a Superclass Reference

Substituting a subclass instance for its superclass is called "upcasting". This is considering, in a UML class diagram, bracket is often fatigued below its superclass. Upcasting is e'er safe because a subclass case possesses all the backdrop of its superclass and tin practice whatsoever its superclass can exercise. The compiler checks for valid upcasting and issues mistake "incompatible types" otherwise. For example,

Circumvolve c1 = new Cylinder(1.1, 2.ii);   Circumvolve c2 = new String();        
Downcasting a Substituted Reference to Its Original Class

You can revert a substituted example dorsum to a bracket reference. This is called "downcasting". For example,

Circle c1 = new Cylinder(1.ane, 2.2);   Cylinder cy1 = (Cylinder) c1;        

Downcasting requires explicit blazon casting operator in the form of prefix operator (new-blazon). Downcasting is not ever rubber, and throws a runtime ClassCastException if the instance to exist downcasted does not belong to the right subclass. A bracket object can be substituted for its superclass, simply the reverse is not true.

Another Case on Upcasting and Downcasting

OOP_PolymorphismABC.png

public course          A          {    public A() {         System.out.println("Constructed an example of A");    }    @Override    public String toString() {       render "This is A";    } }
public form          B extends A          {    public B() {         super();       Organization.out.println("Constructed an instance of B");    }    @Override    public String toString() {       return "This is B";    } }
public class          C extends B          {    public C() {         super();       System.out.println("Constructed an instance of C");    }    @Override    public String toString() {       return "This is C";    } }

The following plan tests the upcasting an downcasting (refer to the higher up example diagram):

public grade          TestCasting          {    public static void main(String[] args) {       A a1 = new C();             Synthetic an instance of A                        Arrangement.out.println(a1);                B b1 = (B)a1;            System.out.println(b1);                C c1 = (C)b1;            System.out.println(c1);                 A a2 = new B();                       Organization.out.println(a2);                B b2 = (B)a2;           C c2 = (C)a2;          compilation okay, but runtime error:              } }
Casting Operator

Compiler may not be able to observe error in explicit cast, which volition be detected simply at runtime. For example,

Circumvolve c1 = new Circle(5); Point p1 = new Point();   c1 = p1;          compilation fault: incompatible types (Betoken is not a bracket of Circle)          c1 = (Circle)p1;        

The "instanceof" Operator

Java provides a binary operator chosen instanceof which returns true if an object is an instance of a particular class. The syntax is as follows:

          anObject          instanceof          aClass        
Circle c1 = new Circle(); System.out.println(c1 instanceof Circle);     if (c1 instanceof Circumvolve) { ...... }

An instance of bracket is also an instance of its superclass. For example,

Circle c1 = new Circle(1.1); Cylinder cy1 = new Cylinder(2.2, 3.3); System.out.println(c1 instanceof Circumvolve);     System.out.println(c1 instanceof Cylinder);   System.out.println(cy1 instanceof Cylinder);  System.out.println(cy1 instanceof Circumvolve);      Circle c2 = new Cylinder(4.four, 5.5); Organization.out.println(c2 instanceof Circle);     System.out.println(c2 instanceof Cylinder);        

Summary of Polymorphism

  1. A subclass instance processes all the attributes operations of its superclass. When a superclass instance is expected, it tin can be substituted by a bracket instance. In other words, a reference to a grade may hold an example of that grade or an example of 1 of its subclasses - it is called substitutability.
  2. If a bracket instance is assign to a superclass reference, you can invoke the methods defined in the superclass only. You cannot invoke methods defined in the subclass.
  3. However, the substituted case retains its own identity in terms of overridden methods and hiding variables. If the subclass overrides methods in the superclass, the bracket's version will be executed, instead of the superclass's version.

Exercises

LINK TO EXERCISES

Abstruse Classes & Interfaces

The abstract Method and abstruse class

In the above examples of Shape and Monster, nosotros encountered a problem when nosotros create instances of Shape and Monster and run the getArea() or attack(). This can exist resolved via abstract method and abstruse course.

An abstract method is a method with merely signature (i.e., the method proper noun, the list of arguments and the render blazon) without implementation (i.e., the method's body). You lot employ the keyword abstruse to declare an abstract method.

For example, in the Shape course, we can declare abstract methods getArea(), draw(), etc, every bit follows:

          abstract          public grade          Shape          {    ......    ......          abstract          public double getArea();          abstruse          public double getPerimeter();          abstract          public void draw(); }

Implementation of these methods is NOT possible in the Shape class, as the bodily shape is not nonetheless known. (How to compute the area if the shape is non known?) Implementation of these abstract methods will exist provided later once the actual shape is known. These abstract methods cannot be invoked because they have no implementation.

OOP_PolymorphismAbstractShape.png

A grade containing 1 or more abstract methods is chosen an abstract course. An abstract course must exist declared with a class-modifier abstract. An abstract grade CANNOT be instantiated, as its definition is non complete.

UML Notation: abstruse class and method are shown in italic.

Abstract Class EG. ane: Shape and its Subclasses

Let us rewrite our Shape class as an abstract class, containing an abstruse method getArea() as follows:

The abstract Superclass Shape.java
            abstruse          public class          Shape          {        private String colour;            public Shape (String colour) {       this.colour = color;    }            @Override    public String toString() {       return "Shape[colour=" + color + "]";    }                  abstract public double getArea();          }

An abstruse class is incomplete in its definition, since the implementation of its abstract methods is missing. Therefore, an abstract class cannot exist instantiated. In other words, you cannot create instances from an abstruse class (otherwise, you volition take an incomplete instance with missing method'southward trunk).

To utilise an abstract course, you have to derive a subclass from the abstruse class. In the derived subclass, you have to override the abstract methods and provide implementation to all the abstruse methods. The subclass derived is at present complete, and tin can be instantiated. (If a subclass does non provide implementation to all the abstract methods of the superclass, the subclass remains abstract.)

This property of the abstract class solves our before problem. In other words, you can create instances of the subclasses such as Triangle and Rectangle, and upcast them to Shape (so equally to program and operate at the interface level), only you lot cannot create case of Shape, which avoid the pitfall that we have faced. For example,

public class          TestShape          {    public static void chief(String[] args) {       Shape s1 = new Rectangle("red", iv, 5);       System.out.println(s1);       Organisation.out.println("Area is " + s1.getArea());              Shape s2 = new Triangle("bluish", 4, 5);       System.out.println(s2);       System.out.println("Area is " + s2.getArea());                        Shape s3 = new Shape("green");              } }

In summary, an abstract grade provides a template for further development. The purpose of an abstruse form is to provide a common interface (or protocol, or contract, or understanding, or naming convention) to all its subclasses. For example, in the abstract class Shape, you lot tin can ascertain abstruse methods such as getArea() and draw(). No implementation is possible because the actual shape is not known. Yet, by specifying the signature of the abstruse methods, all the subclasses are forced to apply these methods' signature. The subclasses could provide the proper implementations.

Coupled with polymorphism, yous can upcast bracket instances to Shape, and plan at the Shape level, i,eastward., program at the interface. The separation of interface and implementation enables improve software design, and ease in expansion. For example, Shape defines a method called getArea(), which all the subclasses must provide the correct implementation. You can enquire for a getArea() from whatever subclasses of Shape, the right expanse will be computed. Furthermore, you application tin can be extended easily to adjust new shapes (such as Circle or Square) by deriving more subclasses.

Rule of Thumb: Program at the interface, non at the implementation. (That is, brand references at the superclass; substitute with subclass instances; and invoke methods defined in the superclass just.)

Notes:

  • An abstract method cannot be alleged final, every bit terminal method cannot be overridden. An abstruse method, on the other hand, must be overridden in a descendant before information technology can be used.
  • An abstract method cannot be private (which generates a compilation fault). This is considering individual method are not visible to the subclass and thus cannot be overridden.

Abstract Grade EG. two: Monster

We shall define the superclass Monster as an abstract class, containing an abstract method assail(). The abstract class cannot be instantiated (i.e., creating instances).

            abstract          public class          Monster          {    private Cord name;           public Monster(String proper name) {       this.name = name;    }               abstract public Cord attack();          }

The Coffee's interface

A Java interface is a 100% abstract superclass which define a set of methods its subclasses must back up. An interface contains only public abstract methods (methods with signature and no implementation) and possibly constants (public static final variables). Y'all have to apply the keyword "interface" to define an interface (instead of keyword "class" for normal classes). The keyword public and abstract are not needed for its abstract methods as they are mandatory.

(JDK viii introduces default and static methods in the interface. JDK 9 introduces private methods in the interface. These volition non exist covered in this article.)

Similar to an abstract superclass, an interface cannot be instantiated. You lot accept to create a "subclass" that implements an interface, and provide the actual implementation of all the abstract methods.

Unlike a normal form, where you use the keyword "extends" to derive a subclass. For interface, we employ the keyword "implements" to derive a subclass.

An interface is a contract for what the classes can do. It, however, does not specify how the classes should do it.

An interface provides a course, a protocol, a standard, a contract, a specification, a set of rules, an interface, for all objects that implement information technology. It is a specification and rules that any object implementing information technology agrees to follow.

In Java, abstruse grade and interface are used to carve up the public interface of a class from its implementation so as to allow the programmer to program at the interface instead of the diverse implementation.

Interface Naming Convention: Use an adjective (typically ends with "able") consisting of one or more words. Each give-and-take shall be initial capitalized (camel-case). For example, Serializable, Extenalizable, Movable, Clonable, Runnable, etc.

Interface EG. ane: Shape Interface and its Implementations

Nosotros can re-write the abstract superclass Shape into an interface, containing only abstract methods, every bit follows:

OOP_InterfaceShape.png

UML Notations: Abstract classes, Interfaces and abstruse methods are shown in italics. Implementation of interface is marked by a dash-pointer leading from the subclasses to the interface.

            public          interface          Shape          {                double getArea();          }
            public grade          Rectangle implements Shape          {          individual int length, width;         public Rectangle(int length, int width) {       this.length = length;       this.width = width;    }         @Override    public Cord toString() {       return "Rectangle[length=" + length + ",width=" + width + "]";    }                   @Override    public double getArea()          {       return length * width;    } }
            public class          Triangle implements Shape          {        private int base of operations, height;         public Triangle(int base, int elevation) {       this.base = base;       this.height = height;    }         @Override    public String toString() {       return "Triangle[base of operations=" + base of operations + ",height=" + acme + "]";    }                   @Override    public double getArea()          {       render 0.5 * base of operations * pinnacle;    } }

A test driver is as follows:

public class          TestShape          {    public static void principal(String[] args) {       Shape s1 = new Rectangle(1, ii);         Organization.out.println(s1);              Arrangement.out.println("Area is " + s1.getArea());               Shape s2 = new Triangle(iii, 4);         Organisation.out.println(s2);              Organisation.out.println("Area is " + s2.getArea());                                 } }

Interface EG. ii: Movable Interface and its Implementations

Suppose that our awarding involves many objects that can move. We could ascertain an interface called movable, containing the signatures of the various motion methods.

OOP_InterfaceMovable.png

Interface Moveable.java
            public          interface          Movable          {          public void moveUp();        public void moveDown();    public void moveLeft();    public void moveRight(); }

Similar to an abstract course, an interface cannot exist instantiated; considering it is incomplete (the abstract methods' body is missing). To utilize an interface, again, y'all must derive subclasses and provide implementation to all the abstract methods declared in the interface. The subclasses are now complete and tin can be instantiated.

MovablePoint.java

To derive subclasses from an interface, a new keyboard "implements" is to exist used instead of "extends" for deriving subclasses from an ordinary class or an abstract class. It is important to note that the subclass implementing an interface need to override ALL the abstruse methods defined in the interface; otherwise, the subclass cannot exist compiled. For example,

            public class          MovablePoint implements Movable          {        private int x, y;                  public MovablePoint(int x, int y) {       this.ten = x;       this.y = y;    }          @Override    public String toString() {       return "(" + x + "," + y + ")";    }         @Override    public void moveUp() {       y--;    }    @Override    public void moveDown() {       y++;    }    @Override    public void moveLeft() {       x--;    }    @Override    public void moveRight() {       x++;    } }

Other classes in the application can similarly implement the Movable interface and provide their own implementation to the abstract methods defined in the interface Movable.

TestMovable.java

Nosotros can also upcast subclass instances to the Movable interface, via polymorphism, similar to an abstract form.

public class          TestMovable          {    public static void principal(String[] args) {       MovablePoint p1 = new MovablePoint(1, 2);       System.out.println(p1);              p1.moveDown();       System.out.println(p1);              p1.moveRight();       System.out.println(p1);                         Movable          p2 = new          MovablePoint(iii, 4);         p2.moveUp();       System.out.println(p2);               MovablePoint p3 =          (MovablePoint)p2;          System.out.println(p3);           } }

Implementing Multiple Interfaces

As mentioned, Java supports only unmarried inheritance. That is, a subclass tin be derived from 1 and just one superclass. Java does not support multiple inheritance to avert inheriting conflicting backdrop from multiple superclasses. Multiple inheritance, notwithstanding, does accept its identify in programming.

A bracket, nonetheless, tin implement more than one interfaces. This is permitted in Java as an interface only defines the abstract methods without the actual implementations and less likely leads to inheriting conflicting properties from multiple interfaces. In other words, Java indirectly supports multiple inheritances via implementing multiple interfaces. For example,

public class          Circle extends Shape implements Movable, Adjustable          {                ....... }

interface Formal Syntax

The formal syntax for declaring interface is:

[public|protected|package]          interface          interfaceName          [extends          superInterfaceName]          {                    static last          ...;         ...          }        

All methods in an interface shall be public and abstract (default). You cannot use other access modifier such equally private, protected and default, or modifiers such as static, final.

All fields shall be public, static and final (default).

An interface may "extends" from a super-interface.

UML Notation: The UML note uses a solid-line arrow linking the subclass to a concrete or abstruse superclass, and dashed-line pointer to an interface every bit illustrated. Abstruse class and abstract method are shown in italics.

OOP_UMLSuperclass.png

Why interfaces?

An interface is a contract (or a protocol, or a mutual understanding) of what the classes can do. When a class implements a certain interface, it promises to provide implementation to all the abstract methods declared in the interface. Interface defines a prepare of mutual behaviors. The classes implement the interface hold to these behaviors and provide their own implementation to the behaviors. This allows you to programme at the interface, instead of the actual implementation. 1 of the principal usage of interface is provide a communication contract between two objects. If y'all know a class implements an interface, and so you know that class contains physical implementations of the methods declared in that interface, and you are guaranteed to be able to invoke these methods safely. In other words, two objects can communicate based on the contract defined in the interface, instead of their specific implementation.

Secondly, Java does non back up multiple inheritance (whereas C++ does). Multiple inheritance permits yous to derive a subclass from more than than one straight superclass. This poses a problem if two direct superclasses have conflicting implementations. (Which one to follow in the subclass?). However, multiple inheritance does take its place. Coffee does this by permitting you lot to "implements" more than one interfaces (but you can only "extends" from a single superclass). Since interfaces contain simply abstruse methods without actual implementation, no conflict can arise among the multiple interfaces. (Interface can hold constants simply is non recommended. If a subclass implements two interfaces with conflicting constants, the compiler will flag out a compilation error.)

Interface vs. Abstract Superclass

Which is a better design: interface or abstract superclass? At that place is no clear answer.

Employ abstract superclass if there is a clear class bureaucracy. Abstract class can incorporate partial implementation (such as instance variables and methods). Interface cannot contain any implementation, just merely defines the behaviors.

As an case, Java's thread can exist built using interface Runnable or superclass Thread.

Exercises

LINK TO EXERCISES ON POLYMORPHISM, ABSTRACT CLASSES AND INTERFACES

(Advanced) Dynamic Binding or Late Binding

We oftentimes treat an object non as its own type, merely as its base type (superclass or interface). This allows you lot to write codes that do non depends on a specific implementation type. In the Shape example, we can ever apply getArea() and do not have to worry whether they are triangles or circles.

This, however, poses a new problem. The compiler cannot know at compile fourth dimension precisely which piece of codes is going to be executed at run-time (e.g., getArea() has different implementation for Rectangle and Triangle).

In the procedural language like C, the compiler generates a call to a specific function name, and the linkage editor resolves this call to the accented address of the code to exist executed at run-time. This machinery is called static binding (or early binding).

To support polymorphism, object-oriented language uses a different mechanism chosen dynamic binding (or tardily-binding or run-time binding). When a method is invoked, the code to be executed is but determined at run-time. During the compilation, the compiler checks whether the method exists and performs type check on the arguments and return type, but does not know which piece of codes to execute at run-time. When a bulletin is sent to an object to invoke a method, the object figures out which piece of codes to execute at run-time.

Although dynamic binding resolves the trouble in supporting polymorphism, it poses another new problem. The compiler is unable to check whether the type casting operator is safety. It can simply exist checked during runtime (which throws a ClassCastException if the type bank check fails).

JDK 1.5 introduces a new characteristic called generics to tackle this issue. We shall discuss this problem and generics in details in the subsequently affiliate.

Exercises

LINK TO EXERCISES

(Advanced) Object-Oriented Blueprint Problems

Encapsulation, Coupling & Cohesion

In OO Design, information technology is desirable to design classes that are tightly encapsulated, loosely coupled and highly cohesive, so that the classes are piece of cake to maintain and suitable for re-use.

Encapsulation refers to keeping the data and method inside a class such users practise not access the data straight just via the public methods. Tight encapsulation is desired, which can be achieved by declaring all the variable individual, and providing public getter and setter to the variables. The benefit is you have complete control on how the data is to be read (e.g., in how format) and how to the data is to be changed (east.grand., validation).

[TODO] Instance: Time course with private variables hour (0-23), minute (0-59) and second (0-59); getters and setters (throws IllegalArgumentException). The internal time could also exist stored as the number of seconds since midnight for ease of operation (information hiding).

Information Hiding: Some other key benefit of tight encapsulation is data hiding, which means that the users are not aware (and exercise not need to exist enlightened) of how the data is stored internally.

The benefit of tight encapsulation out-weights the overhead needed in additional method calls.

Coupling refers to the caste to which one form relies on knowledge of the internals of another form. Tight coupling is undesirable considering if i course changes its internal representations, all the other tightly-coupled classes need to be rewritten.

[TODO] Example: A grade uses Time and relies on the variables 60 minutes, minute and 2d.

Conspicuously, Loose Coupling is often associated with tight encapsulation. For example, well-divers public method for accessing the data, instead of directly access the data.

Cohesion refers to the caste to which a class or method resists being cleaved down into smaller pieces. High degree of cohesion is desirable. Each class shall be designed to model a single entity with its focused set of responsibilities and perform a drove of closely related tasks; and each method shall accomplish a single job. Low cohesion classes are hard to maintain and re-use.

[TODO] Instance of low cohesion: Book and Author in one class, or Car and Driver in i class.

Once more, high cohesion is associated with loose coupling. This is because a highly cohesive class has fewer (or minimal) interactions with other classes.

"Is-a" vs. "has-a" relationships

"Is-a" relationship: A bracket object processes all the data and methods from its superclass (and it could take more). We can say that a subclass object is-a superclass object (is more than a superclass object). Refer to "polymorphism".

"has-a" relationship: In composition, a class contains references to other classes, which is known as "has-a" human relationship.

You can use "is-a" and 'has-a" to exam whether to pattern the classes using inheritance or limerick.

Programme at the interface specification, not the implementation

Refer to polymorphism

LINK TO Coffee REFERENCES & RESOURCES

adamsdegainge.blogspot.com

Source: https://www3.ntu.edu.sg/home/ehchua/programming/java/J3b_OOPInheritancePolymorphism.html

0 Response to "Like a Family Tree, a ________ Shows the Inheritance Relationship Between Classes"

Post a Comment

Iklan Atas Artikel

Iklan Tengah Artikel 1

Iklan Tengah Artikel 2

Iklan Bawah Artikel