Skip to content
Snippets Groups Projects
Commit 0a199b4f authored by Goik Martin's avatar Goik Martin
Browse files

refining equals()

parent c8080b7d
No related branches found
No related tags found
No related merge requests found
......@@ -29,8 +29,9 @@
}</programlisting></td>
<td valign="top"><programlisting language="none">public class Circle {
// Center coordinate <coref linkend="sda_inherit_fig_codeDuplicate-1-co"/>
private <emphasis role="red">double x</emphasis>;
// Center coordinate
private <emphasis role="red">double x</emphasis>; <coref
linkend="sda_inherit_fig_codeDuplicate-1-co"/>
private <emphasis role="red">double y</emphasis>;
private double radius; <co linkends="sda_inherit_fig_codeDuplicate-3"
......@@ -437,15 +438,24 @@ public Rectangle(double x, double y,
<programlisting language="java">public class Rectangle extends Shape {
@Override public void move(int xTrans, int yTrans) {
// I'm so dumb!
...
}</programlisting>
</figure>
<para>Solution: Prohibit overriding <methodname>move()</methodname> in
superclass <code language="java">Shape</code>:</para>
<figure xml:id="sda_inherit_fig_shapeMoveProblemSubclassSolution">
<title>Solution: <emphasis role="red">final</emphasis> prevents
overriding</title>
<programlisting language="none">... public <emphasis role="red">final</emphasis> void move(final int xTrans, final int yTrans) {
x += xTrans;
y += yTrans;
} ...</programlisting>
<programlisting language="none">public abstract class Shape {
... public <emphasis role="red">final</emphasis> void move(final int xTrans, final int yTrans) {
x += xTrans;
y += yTrans;
}...</programlisting>
<programlisting language="java">public class Rectangle extends Shape {
// Syntax error: 'move(int, int)' cannot override
// 'move(int, int)' in 'inherit.Shape'; overridden method is final
@Override public void move(int xTrans, int yTrans) {...</programlisting>
</figure>
</section>
......@@ -457,20 +467,20 @@ public Rectangle(double x, double y,
<informaltable border="0">
<tr>
<td valign="top"><programlisting language="java"> /**
<td valign="top"><programlisting language="java">public class Rectangle extents Shape {
/**
* Calculate the area.
* @return The rectangle's area
*/
@Override
public double getArea() {
return width * height;
}</programlisting></td>
<td valign="top"><programlisting language="java"> /**
<td valign="top"><programlisting language="java">public class Circle extents Shape {
/**
* Calculate the area.
* @return The circle's area
*/
@Override
public double getArea() {
return Math.PI * radius * radius;
}</programlisting></td>
......@@ -479,19 +489,22 @@ public Rectangle(double x, double y,
</figure>
<figure xml:id="sda_inherit_fig_shapePolymorphicAreaCall">
<title>Wanted: Polymorphic <methodname>getArea()</methodname>
<title>Desired: Polymorphic <methodname>getArea()</methodname>
call</title>
<programlisting language="none">final Shape[] shapes <co
linkends="sda_inherit_fig_shapePolymorphicAreaCall-1"
xml:id="sda_inherit_fig_shapePolymorphicAreaCall-1-co"/> = {new Circle(1, 1, 2.) <co
xml:id="sda_inherit_fig_shapePolymorphicAreaCall-1-co"/> = {
new Circle(1, 1, 2.) <co
linkends="sda_inherit_fig_shapePolymorphicAreaCall-2"
xml:id="sda_inherit_fig_shapePolymorphicAreaCall-2-co"/>,
new Rectangle(1, -1, 2., 3.)<coref
new Rectangle(1, -1, 2., 3.)<coref
linkend="sda_inherit_fig_shapePolymorphicAreaCall-2-co"/>};
for (final Shape s : shapes) {
System.out.println(s.toString() + ": <emphasis role="red">area = " + s.getArea()</emphasis>);
System.out.println(s.toString() + ": <emphasis role="red">area = " + s.getArea()</emphasis>); <co
linkends="sda_inherit_fig_shapePolymorphicAreaCall-3"
xml:id="sda_inherit_fig_shapePolymorphicAreaCall-3-co"/>
}</programlisting>
<screen>Circle at (1.0|1.0), radius= 2.0: <emphasis role="red">area = 12.566370614359172</emphasis>
......@@ -511,28 +524,34 @@ Rectangle at (1.0|-1.0), width= 2.0, height=3.0: <emphasis role="red">area = 6.0
<classname>Circle</classname>. We can thus assign both
<classname>Circle</classname> and <classname>Rectangle</classname>
instances to variables (or array elements) of type
<classname>Shape</classname> by upcasting.</para>
<classname>Shape</classname> by means of upcasting.</para>
</callout>
<callout arearefs="sda_inherit_fig_shapePolymorphicAreaCall-3-co"
xml:id="sda_inherit_fig_shapePolymorphicAreaCall-3">
<para>Polymorphic dispatch: Depending on the object's type the <xref
linkend="glo_Java"/> runtime will automatically choose either
<classname>Rectangle</classname>.<methodname>toString()</methodname>/
<classname>Rectangle</classname>.<methodname>getArea()</methodname> or
<classname>Circle</classname>.<methodname>getArea()</methodname> /
<classname>Circle</classname>.<methodname>toString()</methodname>/
<classname>Circle</classname>.<methodname>getArea()</methodname>
respectively.</para>
</callout>
</calloutlist>
<figure xml:id="sda_inherit_fig_getAreaPolymorphicProblem">
<title>Problem</title>
<title>Problems:</title>
<itemizedlist>
<listitem>
<para>No such <methodname>getArea()</methodname> method in class
<classname>Shape</classname>.</para>
<para>No meaningful <methodname>getArea()</methodname> method in
class <classname>Shape</classname> possible.</para>
</listitem>
<listitem>
<para>No meaningful implementation in
<classname>Shape</classname>.</para>
</listitem>
<listitem>
<para>Meaningful implementations in both subclasses
<classname>Rectangle</classname> and
<classname>Circle</classname>.</para>
<para>Meaningful implementations exist both in subclass<classname>
Rectangle</classname> and <classname>Circle</classname>.</para>
</listitem>
</itemizedlist>
......@@ -595,20 +614,27 @@ Rectangle at (1.0|-1.0), width= 2.0, height=3.0: <emphasis role="red">area = 6.0
<para>Superclass <classname>Shape</classname> contains an <code
language="java">abstract</code> method and must thus itself be
declared <code language="java">abstract</code> as well.</para>
<note>
<para>You cannot create instances of <code
language="java">abstract</code> classes. You may however create
instances of derived non-<code language="java">abstract</code>
classes.</para>
</note>
</callout>
<callout arearefs="sda_inherit_fig_implementAbstractGetArea-2-co"
xml:id="sda_inherit_fig_implementAbstractGetArea-2">
<para>Method <classname>getArea()</classname> cannot be implemented in
a meaningful way. Its <code language="java">abstract</code> modifier
is a promise that any concrete (= non-<code
is a promise that some concrete (= non-<code
language="java">abstract</code>) subclass will either offer an
implementation of <classname>getArea()</classname> or will have a
parent class doing so.</para>
implementation of <classname>getArea()</classname> or will have an
intermediate parent class doing so.</para>
<para>The <code language="java">abstract</code> keyword requires a
corresponding implementation in any derived non-<code
language="java">abstract</code> subclass.</para>
<para>In other words: The <code language="java">abstract</code>
keyword requires a corresponding implementation in some derived
non-<code language="java">abstract</code> subclass.</para>
</callout>
<callout arearefs="sda_inherit_fig_implementAbstractGetArea-3-co"
......@@ -923,7 +949,8 @@ public abstract class Shape <co
final protected long <emphasis role="red">creationTime</emphasis> <co
linkends="sda_inherit_fig_protectedCreationTime-2"
xml:id="sda_inherit_fig_protectedCreationTime-2-co"/>= System.nanoTime();
... }
...
}
------------------------------------------------
<emphasis role="red">package model.sub</emphasis>;
public class Rectangle <co linkends="sda_inherit_fig_protectedCreationTime-3"
......@@ -935,36 +962,37 @@ public class Rectangle <co linkends="sda_inherit_fig_protectedCreationTime-3"
linkends="sda_inherit_fig_protectedCreationTime-4"
xml:id="sda_inherit_fig_protectedCreationTime-4-co"/>);
return width * height;
} ... }</programlisting>
} ...
}</programlisting>
</figure>
<calloutlist>
<callout arearefs="sda_inherit_fig_protectedCreationTime-1-co"
xml:id="sda_inherit_fig_protectedCreationTime-1">
<para>Defining superclass <classname>Shape</classname> in package
<code language="java">model</code>.</para>
</callout>
<calloutlist>
<callout arearefs="sda_inherit_fig_protectedCreationTime-1-co"
xml:id="sda_inherit_fig_protectedCreationTime-1">
<para>Defining superclass <classname>Shape</classname> in package
<code language="java">model</code>.</para>
</callout>
<callout arearefs="sda_inherit_fig_protectedCreationTime-2-co"
xml:id="sda_inherit_fig_protectedCreationTime-2">
<para>Defining a <code language="java">protected</code> instance
attribute <property>creationTime</property> in superclass
<classname>Shape</classname>.</para>
</callout>
<callout arearefs="sda_inherit_fig_protectedCreationTime-2-co"
xml:id="sda_inherit_fig_protectedCreationTime-2">
<para>Defining a <code language="java">protected</code> instance
attribute <property>creationTime</property> in superclass
<classname>Shape</classname>.</para>
</callout>
<callout arearefs="sda_inherit_fig_protectedCreationTime-3-co"
xml:id="sda_inherit_fig_protectedCreationTime-3">
<para>Deriving class <classname>Rectangle</classname> in different
package <code language="java">model.sub</code> from superclass <code
language="java">Shape</code>.</para>
</callout>
<callout arearefs="sda_inherit_fig_protectedCreationTime-3-co"
xml:id="sda_inherit_fig_protectedCreationTime-3">
<para>Deriving class <classname>Rectangle</classname> in different
package <code language="java">model.sub</code> from superclass <code
language="java">Shape</code>.</para>
</callout>
<callout arearefs="sda_inherit_fig_protectedCreationTime-4-co"
xml:id="sda_inherit_fig_protectedCreationTime-4">
<para>Accessing superclass attribute
<property>creationTime</property> across package boundary.</para>
</callout>
</calloutlist>
</figure>
<callout arearefs="sda_inherit_fig_protectedCreationTime-4-co"
xml:id="sda_inherit_fig_protectedCreationTime-4">
<para>Accessing superclass attribute <property>creationTime</property>
across package boundary.</para>
</callout>
</calloutlist>
<qandaset defaultlabel="qanda" xml:id="sd1_qanda_protectedPackagePrivate">
<title><code language="java">protected</code> vs. <quote>package
......@@ -1159,14 +1187,15 @@ public class Rectangle
<tr>
<td valign="top"><programlisting language="java">public static void main(String[] args) {
final Shape[] shapes = {new Circle(1, 1, 2.),
final Shape[] shapes = {
new Circle(1, 1, 2.),
new Rectangle(1, -1, 2., 3.)};
print(shapes);
}
static void print(final Shape[] shapes) {
for (final Shape s : shapes) {
if (s instanceof Rectangle) {
System.out.println("Type Rectangle");
System.out.println("Type Rectangle");
} else if (s instanceof Circle) {
System.out.println("Type Circle");
}
......@@ -1179,6 +1208,57 @@ Type Rectangle</screen></td>
</informaltable>
</figure>
<figure xml:id="sd1_inherit_fig_shapeDefineEquals">
<title>Defining <methodname>equals(...)</methodname> of
<classname>Shape</classname> instances </title>
<para>Two <classname>Shape</classname> instances shall be considered
equal if:</para>
<itemizedlist>
<listitem>
<para>Both instances are of common type <abbrev>i.e.</abbrev> either
<classname>Rectangle</classname> or
<classname>Circle</classname>.</para>
</listitem>
<listitem>
<para>Their center coordinates match within a threshold of
<inlineequation>
<m:math display="inline">
<m:msup>
<m:mi>10</m:mi>
<m:mrow>
<m:mo>-</m:mo>
<m:mi>15</m:mi>
</m:mrow>
</m:msup>
</m:math>
</inlineequation>.</para>
</listitem>
<listitem>
<para><code language="java">width</code> and <code
language="java">height</code> or <code language="java">radius</code>
match within a threshold of <inlineequation>
<m:math display="inline">
<m:msup>
<m:mi>10</m:mi>
<m:mrow>
<m:mo>-</m:mo>
<m:mi>15</m:mi>
</m:mrow>
</m:msup>
</m:math>
</inlineequation>.</para>
</listitem>
</itemizedlist>
</figure>
<figure xml:id="sd1_inherit_fig_equalByCoordinate">
<title>Comparing center coordinates</title>
......@@ -1191,6 +1271,27 @@ Type Rectangle</screen></td>
...</programlisting>
</figure>
<figure xml:id="sd1_inherit_fig_rectangleEquals">
<title>Implementing <classname>Rectangle</classname>.<methodname
xlink:href="https://docs.oracle.com/javase/9/docs/api/java/lang/Object.html#equals-java.lang.Object-">equals()</methodname></title>
<programlisting language="java">public class Rectangle extends Shape {
@Override public boolean equals(Object o) {
if (o instanceof Rectangle){
final Rectangle oRectangle = (Rectangle) o;
return super.equalCenter(oRectangle) &amp;&amp;
Math.abs(oRectangle.width- width) +
Math.abs(oRectangle.height- height) &lt; 1.E-15;
}
return false;
}
...</programlisting>
<remark>if <code language="java">o == null</code> the expression <code
language="java">o instanceof Rectangle</code> evaluates to <code
language="java">false</code>.</remark>
</figure>
<figure xml:id="sd1_inherit_fig_circleEquals">
<title>Implementing <classname>Circle</classname>.<methodname
xlink:href="https://docs.oracle.com/javase/9/docs/api/java/lang/Object.html#equals-java.lang.Object-">equals()</methodname></title>
......@@ -1200,14 +1301,37 @@ Type Rectangle</screen></td>
if (o instanceof Circle){
final Circle oCircle = (Circle) o;
return super.equalCenter(o) &amp;&amp;
Math.abs(oCircle.radius - radius) &lt; 1.E-15;
Math.abs(oCircle.radius - radius) &lt; 1.E-15;
}
return false;
} ...</programlisting>
</figure>
<remark>if <code language="java">o == null</code> the expression <code
language="java">o instanceof Circle</code> evaluates to <code
language="java">false</code>.</remark>
<figure xml:id="sd1_inherit_fig_testShapeEquals">
<title>Testing equality of <classname>Shape</classname> objects</title>
<informaltable border="0">
<colgroup width="72%"/>
<colgroup width="28%"/>
<tr>
<td valign="top"><programlisting language="java">final Rectangle
r1 = new Rectangle(2, 3, 1,4),
r2 = new Rectangle(2, 3, 2,8),
r3 = new Rectangle(2, 3, 1,4);
final Circle c = new Circle(2,3, 7);
System.out.println("r1.equals(r2): " + r1.equals(r2));
System.out.println("r1.equals(r3): " + r1.equals(r3));
System.out.println("c.equals(r1): " + c.equals(r1));</programlisting></td>
<td valign="top"><screen>r1.equals(r2): false
r1.equals(r3): true
c.equals(r1): false</screen></td>
</tr>
</informaltable>
</figure>
</section>
</chapter>
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment