From 0a199b4f7ece069fd931d82d75d01fd0a97303e3 Mon Sep 17 00:00:00 2001
From: Martin Goik <goik@hdm-stuttgart.de>
Date: Wed, 10 Jan 2018 11:25:47 +0100
Subject: [PATCH] refining equals()

---
 Doc/Sd1/inheritance.xml | 258 +++++++++++++++++++++++++++++-----------
 1 file changed, 191 insertions(+), 67 deletions(-)

diff --git a/Doc/Sd1/inheritance.xml b/Doc/Sd1/inheritance.xml
index 6b162c21c..b53d71c42 100644
--- a/Doc/Sd1/inheritance.xml
+++ b/Doc/Sd1/inheritance.xml
@@ -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>
-- 
GitLab