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
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
), andgender
(char
of either'm'
or'f'
- you might besides apply aboolean
variable chosenisMale
having value oftrue
orfalse
). - A constructor to initialize the
name
,email
andgender
with the given values.
(There is no default constructor, equally there is no default value forproper name
,email
andgender
.) - Public getters/setters:
getName()
,getEmail()
,setEmail()
, andgetGender()
.
(At that place are no setters forname
andgender
, 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
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 theAuthor
class nosotros accept merely created, assuming that each book has exactly ane author),price
(double
), andqty
(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 theAuthor
'stoString()
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
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.
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.
A grade called Circle
is designed every bit shown in the course diagram.
Information technology contains:
- 2
private
member variables: aradius
(double) and aheart
(an instance ofPoint
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 ofthis
instance in the format of "Circle[center=(x,y),radius=r]
". You lot should re-utilize theIndicate
'stoString()
to print "(ten,y)
". - A
altitude(Circumvolve another)
method that returns the distance from the center ofthis
instance to the heart of the givenCircle
instance (chosenanother
).
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,
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 {......}
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
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 asuper()
equally the first statement in a constructor if in that location is nosuper(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
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
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).
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.
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
- A subclass example can be assigned (substituted) to a superclass' reference.
- Once substituted, we can invoke methods defined in the superclass; we cannot invoke methods defined in the subclass.
- 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.
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
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
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
- 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.
- 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.
- 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.
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 bitterminal
method cannot be overridden. Anabstruse
method, on the other hand, must be overridden in a descendant before information technology can be used. - An
abstract
method cannot beprivate
(which generates a compilation fault). This is consideringindividual
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:
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.
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.
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
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