<?xml version="1.0" encoding="UTF-8"?> <chapter annotations="slide" version="5.1" xml:id="sw1ChapterInheritance" xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xila="http://www.w3.org/2001/XInclude/local-attributes" xmlns:xi="http://www.w3.org/2001/XInclude" xmlns:svg="http://www.w3.org/2000/svg" xmlns:ns="http://docbook.org/ns/transclusion" xmlns:m="http://www.w3.org/1998/Math/MathML" xmlns:html="http://www.w3.org/1999/xhtml" xmlns:db="http://docbook.org/ns/docbook"> <title>Inheritance</title> <figure xml:id="sd1_inherit_fig_guessWho"> <title>Guess who's inheriting the money</title> <mediaobject> <imageobject> <imagedata fileref="Fig/guessWho.svg"/> </imageobject> </mediaobject> </figure> <figure xml:id="sd1_inherit_fig_biologicalInherit"> <title>Biology and inheritance</title> <mediaobject> <imageobject> <imagedata fileref="Fig/biologicalInheritance.svg"/> </imageobject> </mediaobject> </figure> <figure xml:id="sda_inherit_fig_DuplicateCode"> <title>Duplicate code</title> <informaltable border="0"> <tr> <td valign="top"><programlisting language="none">public class Rectangle{ // Center coordinate <emphasis role="red">private double x</emphasis>; <co linkends="sda_inherit_fig_DuplicateCode-1" xml:id="sda_inherit_fig_DuplicateCode-1-co"/> <emphasis role="red">private double y</emphasis>; <emphasis role="red">public void move (double dx, double dy){</emphasis> <co linkends="sda_inherit_fig_DuplicateCode-2" xml:id="sda_inherit_fig_DuplicateCode-2-co"/> <emphasis role="red">x += dx; y += dy; }</emphasis> private double width, height; <co linkends="sda_inherit_fig_DuplicateCode-3" xml:id="sda_inherit_fig_DuplicateCode-3-co"/> ... }</programlisting></td> <td valign="top"><programlisting language="none">public class Circle { // Center coordinate <emphasis role="red">private double x</emphasis>; <coref linkend="sda_inherit_fig_DuplicateCode-1-co"/> <emphasis role="red">private double y</emphasis>; <emphasis role="red">public void move (double dx, double dy){</emphasis> <coref linkend="sda_inherit_fig_DuplicateCode-2-co"/> <emphasis role="red">x += dx; y += dy; }</emphasis> private double radius; <coref linkend="sda_inherit_fig_DuplicateCode-3-co"/> ... }</programlisting></td> </tr> </informaltable> <calloutlist role="slideExclude"> <callout arearefs="sda_inherit_fig_DuplicateCode-1-co" xml:id="sda_inherit_fig_DuplicateCode-1"> <para>The center coordinate (<code language="java">x</code>|<code language="java">y)</code> appears both in <classname>Rectangle</classname> and <classname>Circle</classname>.</para> </callout> <callout arearefs="sda_inherit_fig_DuplicateCode-2-co" xml:id="sda_inherit_fig_DuplicateCode-2"> <para>The move(...) method is being defined <emphasis role="bold">identically</emphasis> both in <classname>Rectangle</classname> and <classname>Circle</classname>!</para> </callout> <callout arearefs="sda_inherit_fig_DuplicateCode-3-co" xml:id="sda_inherit_fig_DuplicateCode-3"> <itemizedlist> <listitem> <para><property>width</property> and <property>height</property> only appear in class <classname>Rectangle</classname>.</para> </listitem> <listitem> <para><property>radius</property> only appears in class Circle.</para> </listitem> </itemizedlist> </callout> </calloutlist> </figure> <figure xml:id="sda_inherit_fig_ideaFactorOutCommonCode"> <title>Idea: Centralize common code</title> <itemizedlist> <listitem> <para>Create a parent class <classname>Shape</classname> containing common code portions.</para> </listitem> <listitem> <para>Relate both <classname>Rectangle</classname> and <classname>Circle</classname> to <classname>Shape</classname>.</para> </listitem> </itemizedlist> </figure> <figure xml:id="sda_inherit_fig_shapeCommonSpecific"> <title>Common and specific properties</title> <informaltable border="0"> <colgroup width="40%"/> <colgroup width="20%"/> <colgroup width="40%"/> <tr> <th align="center" colspan="3" valign="top">Common <classname>Rectangle</classname> and <classname>Circle</classname> attributes:</th> </tr> <tr> <td valign="top"/> <td valign="top"><programlisting language="java">double x; double y;</programlisting></td> <td valign="top"/> </tr> <tr> <th align="center" valign="top"><classname>Rectangle</classname> attributes</th> <td/> <th align="center" valign="top"><classname>Circle</classname> attributes</th> </tr> <tr> <td valign="top"><programlisting language="java">double width; double height;</programlisting></td> <td/> <td valign="top"><programlisting language="java">double radius;</programlisting></td> </tr> </informaltable> </figure> <figure xml:id="sda_inherit_fig_shapeInheritPrinciple"> <title>Basic shape inheritance</title> <mediaobject> <imageobject> <imagedata fileref="Fig/shapeBasicInherit.multi.svg"/> </imageobject> </mediaobject> </figure> <figure xml:id="sda_inherit_fig_intro"> <title>Inheritance</title> <itemizedlist> <listitem> <para>Derived classes inherit state and behaviour.</para> </listitem> <listitem> <para>Refinement, specialization.</para> </listitem> <listitem> <para><quote>is-A</quote> relationship:</para> <itemizedlist> <listitem> <para>A rectangle <emphasis role="red">is a</emphasis> shape.</para> </listitem> <listitem> <para>A circle <emphasis role="red">is a</emphasis> shape.</para> </listitem> </itemizedlist> </listitem> </itemizedlist> </figure> <figure xml:id="sda_inherit_fig_shapeSimpleImplement"> <title>Implementing <classname>Shape</classname> hierarchy</title> <informaltable border="0"> <colgroup width="25%"/> <colgroup width="25%"/> <colgroup width="25%"/> <colgroup width="25%"/> <tr> <td valign="top"/> <td colspan="2" valign="top"><programlisting language="java">public class Shape { private double x, y; }</programlisting></td> <td valign="top"/> </tr> <tr> <td colspan="2" valign="top"><programlisting language="java">public class Rectangle extends Shape { private double width; private double height; }</programlisting></td> <td colspan="2" valign="top"><programlisting language="java">public class Circle extends Shape { private double radius; }</programlisting></td> </tr> </informaltable> </figure> <figure xml:id="sda_inherit_fig_createShapesInstances"> <title>Creating instances</title> <programlisting language="java">final double x = 2, y = 3; final Shape shape = new Shape(x, y); final double width = 2, height = 5; final Rectangle r = new Rectangle(x, y , width, height); final double radius = 2.5; final Circle circle = new Circle(x, y , radius);</programlisting> </figure> <figure xml:id="sda_inherit_fig_createShapesConstruct"> <title><classname>Shape</classname> constructor</title> <programlisting language="java">/** * Creating a shape located at center coordinate. * @param x The center's x component. * @param y The center's y component. */ public Shape(double x,double y) { this.x = x; this.y = y; }</programlisting> </figure> <figure xml:id="sda_inherit_fig_createRectangle"> <title>Creating <classname>Rectangle</classname> instances</title> <programlisting language="java">final Rectangle r = new Rectangle(x, y <co linkends="sda_inherit_fig_createRectangle-1" xml:id="sda_inherit_fig_createRectangle-1-co"/>, width, height <co linkends="sda_inherit_fig_createRectangle-2" xml:id="sda_inherit_fig_createRectangle-2-co"/>);</programlisting> <calloutlist> <callout arearefs="sda_inherit_fig_createRectangle-1-co" xml:id="sda_inherit_fig_createRectangle-1"> <para>Center coordinate components <quote>belonging</quote> to superclass <classname>Shape</classname>.</para> </callout> <callout arearefs="sda_inherit_fig_createRectangle-2-co" xml:id="sda_inherit_fig_createRectangle-2"> <para>width and height <quote>belonging</quote> to class <classname>Rectangle</classname>.</para> </callout> </calloutlist> <para>Solution: Nested constructor call. Coming soon ...</para> </figure> <figure xml:id="sda_inherit_fig_RectangleConstructor"> <title><classname>Rectangle</classname> constructor</title> <programlisting language="java">/** * Creating a rectangle at (x|y) of given width and height. * @param x Center's x component. * @param y Center's y component. * @param width Rectangle's width. * @param height Rectangle's height. */ public <link xlink:href="https://gitlab.mi.hdm-stuttgart.de/goik/GoikLectures/blob/master/P/Sd1/Figure/ToString/src/main/java/de/hdm_stuttgart/mi/sd1/shape/model/Rectangle.java">Rectangle</link>(double x, double y, double width, double height) { super(x, y) <co linkends="sda_inherit_fig_RectangleConstructor-1" xml:id="sda_inherit_fig_RectangleConstructor-1-co"/>; this.width = width; this.height = height <co linkends="sda_inherit_fig_RectangleConstructor-2" xml:id="sda_inherit_fig_RectangleConstructor-2-co"/>; }</programlisting> <calloutlist role="slideExclude"> <callout arearefs="sda_inherit_fig_RectangleConstructor-1-co" xml:id="sda_inherit_fig_RectangleConstructor-1"> <para>Passing center coordinate to superclass <classname>Shape</classname>'s constructor.</para> <note> <para>This <emphasis>must</emphasis> be the first statement within <classname>Rectangle</classname>'s constructor.</para> </note> </callout> <callout arearefs="sda_inherit_fig_RectangleConstructor-2-co" xml:id="sda_inherit_fig_RectangleConstructor-2"> <para>Processing <code language="java">width</code> and <code language="java">height</code> in <quote>current</quote> <classname>Rectangle</classname> constructor.</para> </callout> </calloutlist> </figure> <section xml:id="sd1_inherit_sect_overrideEquals"> <title>Overriding <methodname>equals()</methodname> and <methodname>hashCode()</methodname></title> <figure xml:id="sda_inherit_fig_ShapeEquals"> <title><classname>Shape</classname>.<methodname>equals()</methodname></title> <programlisting language="java">public abstract class Shape { ... @Override <co linkends="sda_inherit_fig_ShapeEquals-1" xml:id="sda_inherit_fig_ShapeEquals-1-co"/> public boolean equals(final Object o) { if (o instanceof Shape <emphasis role="red">s</emphasis> <co linkends="sda_inherit_fig_ShapeEquals-2" xml:id="sda_inherit_fig_ShapeEquals-2-co"/>) { return x == <emphasis role="red">s</emphasis>.x && y == <emphasis role="red">s</emphasis>.y; <co linkends="sda_inherit_fig_ShapeEquals-4" xml:id="sda_inherit_fig_ShapeEquals-4-co"/> } else { return false; <co linkends="sda_inherit_fig_ShapeEquals-5" xml:id="sda_inherit_fig_ShapeEquals-5-co"/> } ...</programlisting> <calloutlist role="slideExclude"> <callout arearefs="sda_inherit_fig_ShapeEquals-1-co" xml:id="sda_inherit_fig_ShapeEquals-1"> <para>Promise: The current method overrides a superclass method.</para> </callout> <callout arearefs="sda_inherit_fig_ShapeEquals-2-co" xml:id="sda_inherit_fig_ShapeEquals-2"> <para>Other instance is a <classname>Shape</classname> object?</para> </callout> <callout arearefs="sda_inherit_fig_ShapeEquals-4-co" xml:id="sda_inherit_fig_ShapeEquals-4"> <para>Return <code language="java">true</code> if and only if both center coordinate pairs are equal.</para> </callout> <callout arearefs="sda_inherit_fig_ShapeEquals-5-co" xml:id="sda_inherit_fig_ShapeEquals-5"> <para>Other object distinct from class <classname>Shape</classname>.</para> </callout> </calloutlist> </figure> <figure xml:id="sda_inherit_fig_RectangleEquals"> <title><classname>Rectangle</classname>.<methodname>equals()</methodname></title> <programlisting language="java">public class Rectangle extends Shape { ... @Override public boolean equals(final Object o) { if (o instanceof Rectangle <emphasis role="red">r</emphasis>) { return super.equals(o) <co linkends="sda_inherit_fig_RectangleEquals-1" xml:id="sda_inherit_fig_RectangleEquals-1-co"/> && width == <emphasis role="red">r</emphasis>.width && height == <emphasis role="red">r</emphasis>.height <co linkends="sda_inherit_fig_RectangleEquals-2" xml:id="sda_inherit_fig_RectangleEquals-2-co"/>; } else { return false; } ...</programlisting> <calloutlist role="slideExclude"> <callout arearefs="sda_inherit_fig_RectangleEquals-1-co" xml:id="sda_inherit_fig_RectangleEquals-1"> <para>Including superclass method <classname>Shape</classname>.<methodname>equals()</methodname>.</para> </callout> <callout arearefs="sda_inherit_fig_RectangleEquals-2-co" xml:id="sda_inherit_fig_RectangleEquals-2"> <para>Return <code language="java">true</code> if and only if both <code language="java">width</code> and <code language="java">height</code> pairs are equal.</para> </callout> </calloutlist> </figure> <qandaset defaultlabel="qanda" xml:id="sd1_qanda_stringEqualProblem"> <title>Let me pass, please!</title> <qandadiv> <qandaentry> <question> <para>Consider the following snippet:</para> <programlisting language="java">final Scanner scan = new Scanner(System.in)); do { System.out.print("Please enter password: "); final String password = scan.nextLine(); if (password == "secret") { break; // Leave enclosing do ... while loop } else { System.out.println("Sorry, please try again"); } } while (true); System.out.println("You made it!"); // ...</programlisting> <para>Describe the above code's intended behaviour. Will it succeed? Execute the above code and provide a clue for correcting the underlying flaw.</para> </question> <answer> <para>The user is being asked for a password. Only when entering <code>"secret"</code> access shall be granted.</para> <para>Unfortunately comparing the user's input and the corresponding password is seriously flawed:</para> <programlisting language="java">... if (password == "secret") ...</programlisting> <para>On execution the string literal "secret" will be represented as a <classname xlink:href="javaapi://String">String</classname> object in memory. Each new user input string will be represented as a <emphasis>different</emphasis> <classname xlink:href="javaapi://String">String</classname> object in memory as well.</para> <para>Unfortunately the <quote>==</quote> operator only works as expected for the eight built in primitive <xref linkend="glo_Java"/> types. With respect to class instances variables hold references to objects rather than to the objects' values. The <quote>==</quote> operator compares for object identity rather than for object equality.</para> <para>Two different <classname xlink:href="javaapi://String">String</classname> instances may off course be equal with respect to their <quote>payload</quote> namely the values they both represent. Comparing for object equality rather than for object identity in <xref linkend="glo_Java"/> requires using the <methodname>equals(...)</methodname> method instead. A prerequisite for this to work requires the class authors overriding the <methodname xlink:href="javaapi://Object#equals(java.lang.Object)">Object.equals(Object o)</methodname> method accordingly. This override does exist in class <classname xlink:href="javaapi://String">String</classname>. Within the given context we may thus simply use <methodname xlink:href="javaapi://String#equals(java.lang.Object)">String.equals(Object o)</methodname>:</para> <programlisting language="none">final Scanner scan = new Scanner(System.in)); do { System.out.print("Please enter password: "); final String password = scan.nextLine(); <emphasis role="red">if (password.equals("secret"))</emphasis> { break; // Leave enclosing do ... while loop } else { System.out.println("Sorry, please try again"); } } while (true); System.out.println("You made it!"); // ...</programlisting> </answer> </qandaentry> </qandadiv> </qandaset> <qandaset defaultlabel="qanda" xml:id="sd1_qanda_enomNoEqualsRequired"> <title>Why is == correctly comparing <code language="java">enum</code> instances?</title> <qandadiv> <qandaentry> <question> <para>The preceding exercise <xref linkend="sd1_qanda_stringEqualProblem"/> told us to override <methodname xlink:href="javaapi://Object#equals(java.lang.Object)">Object.equals(Object o)</methodname> when comparing different objects for equality. The == operator on the other hand does compare for object identity rather than semantic equality of objects based on their respective attribute values. However comparing <code language="java">Enum</code> instances for equality using the <code language="java">==</code> operator seems to be sufficient<abbrev> e.g.</abbrev>:</para> <programlisting language="java">Day day = Day.Saturday; // Sufficient using operator == ? if (day == Day.FRIDAY) ... // Or do we require equals? if (day.equals(Day.FRIDAY)) ...</programlisting> <para>Do we thus require an <methodname>equals(Object o)</methodname> method in <code language="java">enum</code> <classname>Day</classname> for comparisons? Give a precise explanation.</para> </question> <answer> <para>In case of <code language="java">enum</code> instances using the <quote>==</quote> operator is sufficient. Due to the way <code language="java">enum</code>'s are being constructed instance creation is limited to the underlying <code language="java">enum</code>'s scope by its implicitly <code language="java">private</code> constructor. It is thus impossible creating new instances outside the respective <code language="java">enum</code>'s scope.</para> <para>Therefore for any two given <code language="java">enum</code> instances both object identity and equality of their respective values is being guaranteed to yield the very same result:</para> <programlisting language="none">MyEnum instance1 = MyEnum.x, // MyEnum representing instance2 = MyEnum.y; // some enum type. final boolean <emphasis role="red">objectIdentity</emphasis> = (instance1 == instance2), // Both boolean values will <emphasis role="red">objectEquality</emphasis> = instance1.equals(instance2); // always be equal.</programlisting> <para>As an aside: In case of <code language="java">null</code> values using the <quote>==</quote> operator avoids <classname>java.lang.NullPointerException</classname> problems:</para> <programlisting language="java">Day day = null; if (day == Day.FRIDAY) ... // Just different, no problems if (day.equals(Day.FRIDAY)) ... // Oops: NPE approaching ...</programlisting> </answer> </qandaentry> </qandadiv> </qandaset> </section> <section xml:id="sd1_inherit_sect_overrideToString"> <title>Overriding toString()</title> <figure xml:id="sda_inherit_fig_shapeInstanceLog"> <title>Printing a <classname>Shape</classname>'s info</title> <informaltable border="0"> <tr> <th>Code</th> <th>Output</th> </tr> <tr> <td valign="top"><programlisting language="none">package inherit; public class Run { public static void main(String[] args) { final Shape shape = new Shape(<emphasis role="red">2.0</emphasis>, <emphasis role="red">3.0</emphasis>); // Center coordinates System.out.println(shape); </programlisting></td> <td valign="top"><screen>inherit.Shape@37d31475</screen><para>Desired:</para><screen><emphasis role="red">(2.0|3.0)</emphasis></screen></td> </tr> </informaltable> </figure> <figure xml:id="sda_inherit_fig_shapeToStringRedefine"> <title>Overwriting <methodname xlink:href="javaapi://Object#toString--">toString()</methodname></title> <mediaobject> <imageobject> <imagedata fileref="Fig/shapeOverrideToStringIde.multi.svg"/> </imageobject> </mediaobject> </figure> <figure xml:id="sda_inherit_fig_shapeExtendObject"> <title><classname>Shape</classname> extending <classname>Object</classname></title> <mediaobject> <imageobject> <imagedata fileref="Fig/shapeRedefineToString.multi.svg"/> </imageobject> </mediaobject> </figure> <figure xml:id="sda_inherit_fig_RectangleLogging"> <title>Logging <classname>Rectangle</classname> instances</title> <informaltable border="0"> <tr> <th>Code</th> <th>Output</th> </tr> <tr> <td valign="top"><programlisting language="java">final Rectangle r = // Center coordinates, new Rectangle(2.0, 3.0, 3.0, 4.0); // width and height System.out.println(r);</programlisting></td> <td valign="top"><screen>(2.0|3.0)</screen><para>Desired:</para><screen><emphasis role="red">Rectangle at </emphasis>(2.0|3.0)<emphasis role="red">, width= 3.0, height=4.0</emphasis></screen></td> </tr> </informaltable> </figure> <figure xml:id="sda_inherit_fig_RectangleOverrideToStringAgain"> <title>Override <methodname>toString()</methodname> in class <classname>Rectangle</classname>.</title> <programlisting language="java">public class Rectangle extends Shape { @Override public String toString() { return "<emphasis role="red">Rectangle at </emphasis>" + super.toString() <co linkends="sda_inherit_fig_RectangleOverrideToStringAgain-1" xml:id="sda_inherit_fig_RectangleOverrideToStringAgain-1-co"/> + "<emphasis role="red">, width= </emphasis>" + <emphasis role="red">width</emphasis> + "<emphasis role="red">, height=</emphasis>" + <emphasis role="red">height</emphasis>; <co linkends="sda_inherit_fig_RectangleOverrideToStringAgain-2" xml:id="sda_inherit_fig_RectangleOverrideToStringAgain-2-co"/> } ...</programlisting> <calloutlist> <callout arearefs="sda_inherit_fig_RectangleOverrideToStringAgain-1-co" xml:id="sda_inherit_fig_RectangleOverrideToStringAgain-1"> <para>The <code language="java" xlink:href="https://docs.oracle.com/javase/tutorial/java/IandI/super.html">super</code> keyword allows for calling the superclass <classname>Shape</classname>'s <methodname>toString()</methodname> method inserting the (2.0|3.0) center coordinate.</para> </callout> <callout arearefs="sda_inherit_fig_RectangleOverrideToStringAgain-2-co" xml:id="sda_inherit_fig_RectangleOverrideToStringAgain-2"> <para>Append class <classname>Rectangle</classname>'s <quote>own</quote> <code language="java">width</code> and <code language="java">height</code> attribute values.</para> </callout> </calloutlist> </figure> <figure xml:id="sda_inherit_fig_rectangleExtendShapa"> <title><classname>Rectangle</classname> extending <classname>Shape</classname></title> <mediaobject> <imageobject> <imagedata fileref="Fig/rectangleRedefineToString.multi.svg"/> </imageobject> </mediaobject> </figure> <figure xml:id="sda_inherit_fig_CircleComplete"> <title>Implementing <classname>Circle</classname>.<methodname>toString()</methodname></title> <programlisting language="java">public class Circle extends Shape { /** * Creating a circle of given center and radius * @param x Center's x component. * @param y Center's y component. * @param radius The circle's radius. */ public Circle(double x,double y, double radius) { super(x, y); this.radius = radius; } @Override public String toString() { return "Circle at " + super.toString() +", radius= " + radius; } private double radius; }</programlisting> </figure> <figure xml:id="sda_inherit_fig_shapeToString"> <title><classname>Shape</classname> and <methodname>toString()</methodname></title> <mediaobject> <imageobject> <imagedata fileref="Fig/shapeToString.svg"/> </imageobject> </mediaobject> </figure> <qandaset defaultlabel="qanda" xml:id="sd1_quanda_inherit_StringBufferNoEqualMethod"> <title><classname>String</classname> vs. <classname>StringBuffer</classname></title> <qandadiv> <qandaentry> <question> <para>Consider two <classname xlink:href="javaapi://StringBuffer">StringBuffer</classname> instances:</para> <informaltable border="1"> <colgroup width="54%"/> <colgroup width="46%"/> <tr> <th>Code</th> <th>Execution result</th> </tr> <tr> <td valign="top"><programlisting language="java">final <link xlink:href="javaapi://StringBuffer">StringBuffer</link> a = new StringBuffer("test"), b = new StringBuffer("test"); System.out.println(a.equals(b));</programlisting></td> <td valign="top"><screen>false</screen></td> </tr> </informaltable> <para>Strangely instances of String behave differently:</para> <informaltable border="1"> <colgroup width="54%"/> <colgroup width="46%"/> <tr> <th>Code</th> <th>Execution result</th> </tr> <tr> <td valign="top"><programlisting language="java">final String a = new String("test"), b = new String("test"); System.out.println(a.equals(b));</programlisting></td> <td valign="top"><screen>true</screen></td> </tr> </informaltable> <para>Explain this different behaviour.</para> <tip> <para>Take a closer look at the <classname xlink:href="javaapi://String">String</classname> and <classname xlink:href="javaapi://StringBuffer">StringBuffer</classname> <xref linkend="glo_API"/> regarding the <methodname>toString()</methodname> method.</para> </tip> </question> <answer> <para>The <classname xlink:href="javaapi://String">String</classname> <xref linkend="glo_API"/> reveals:</para> <screen>public boolean equals (Object anObject) Compares this string to the specified object. The result is true if and only if the argument is not null and is a String object that represents the same sequence of characters as this object. Overrides: equals in class Object Parameters: anObject - The object to compare this String against Returns: true if the given object represents a String equivalent to this string, false otherwise</screen> <para>In a nutshell: Two instances of String will be compared for equality character by character. The superclass <classname xlink:href="javaapi://Object">Object</classname>.<methodname xlink:href="javaapi://Object#equals(java.lang.Object)">equals()</methodname> method is being overridden.</para> <para>In class <classname xlink:href="javaapi://StringBuffer">StringBuffer</classname> we do not find any <methodname>equals()</methodname> method. Thus <classname xlink:href="javaapi://Object">Object</classname>.<methodname xlink:href="javaapi://Object#equals(java.lang.Object)">equals()</methodname> is not being overridden. When comparing two instances of <classname xlink:href="javaapi://StringBuffer">StringBuffer</classname> effectively <classname xlink:href="javaapi://Object">Object</classname>.<methodname xlink:href="javaapi://Object#equals(java.lang.Object)">equals()</methodname> will be executed. Its <xref linkend="glo_API"/> reveals:</para> <screen>public boolean equals (Object obj) Indicates whether some other object is "equal to" this one. ... Parameters: obj - the reference object with which to compare. Returns: true <emphasis role="red">if this object is the same as the obj argument</emphasis>; false otherwise.</screen> <para>Thus two instances of <classname xlink:href="javaapi://StringBuffer">StringBuffer</classname> will be compared for object identity rather than representing the same string value.</para> </answer> </qandaentry> </qandadiv> </qandaset> <qandaset defaultlabel="qanda" xml:id="sd1_quanda_inheritDirectionAlternateImpl"> <title>Alternate implementation of opposite directions</title> <qandadiv> <qandaentry> <question> <para>Provide a different implementation of your <methodname xlink:href="https://gitlab.mi.hdm-stuttgart.de/goik/GoikLectures/blob/master/Doc/Sd1/Ref/ObjectsAndClasses/Enum/Compass_2.0/src/main/java/de/hdm_stuttgart/mi/sd1/direction/Direction.java#L28">opposite()</methodname> from <xref linkend="sd1_qanda_enumDirectionNeighbours"/>. Follow <uri xlink:href="https://stackoverflow.com/questions/5678309/illegal-forward-reference-and-enums#answer-49409377">https://stackoverflow.com/questions/5678309/illegal-forward-reference-and-enums#answer-49409377</uri>. Start by investigating both <methodname xlink:href="http://www.java2s.com/Tutorial/Java/0040__Data-Type/Usingthebuiltinenumerationmethodsvalues.htm">values()</methodname> and <methodname xlink:href="javaapi://Enum#ordinal()">ordinal()</methodname>.</para> </question> <answer> <para>We observe the following ordinal values:</para> <informaltable border="0"> <tr> <td valign="top"><programlisting language="java">public enum Direction { N( 0, "north"), // 0 NE( 45, "north by east"), // 1 E( 90, "east"), // 2 SE(135, "south by east"), // 3 S( 180, "south"), // 4 SW(225, "south by west"), // 5 W( 270, "west"), // 6 NW(315, "north by west"); // 7 ...</programlisting></td> <td valign="top"><programlisting language="none">public Direction opposite() { switch (this) { case N: return S; // <emphasis role="red">0 --> 4</emphasis> case NE: return SW; // <emphasis role="red">1 --> 5</emphasis> case E: return W; // <emphasis role="red">2 --> 6</emphasis> case SE: return NW; // <emphasis role="red">3 --> 7</emphasis> case S: return N; // <emphasis role="red">4 --> 0</emphasis> case SW: return NE; // <emphasis role="red">5 --> 1</emphasis> case W: return E; // <emphasis role="red">6 --> 2</emphasis> case NW: return SE; // <emphasis role="red">7 --> 3</emphasis> ...</programlisting></td> </tr> </informaltable> <para>We are thus left implementing an integer shift <code>(0, 1, 2, 3, 4, 5, 6, 7)</code> to <code>(4, 5, 6, 7, 0, 1, 2, 3)</code>:</para> <programlisting language="java">public Direction <link xlink:href="https://gitlab.mi.hdm-stuttgart.de/goik/GoikLectures/blob/master/Doc/Sd1/Ref/ObjectsAndClasses/Enum/Compass_3.0/src/main/java/de/hdm_stuttgart/mi/sd1/direction/Direction.java#L28">opposite()</link> { return values()[ (ordinal() + 4) % 8]; }</programlisting> </answer> </qandaentry> </qandadiv> </qandaset> </section> <section xml:id="sd1_inherit_sect_final"> <title><code language="java">final</code> methods</title> <figure xml:id="sda_inherit_fig_moveRectangle"> <title>Moving <classname>Shape</classname> instances</title> <mediaobject> <imageobject> <imagedata fileref="Fig/rectangleTranslate.multi.svg"/> </imageobject> </mediaobject> </figure> <figure xml:id="sda_inherit_fig_shapeMove"> <title>Implementing <classname>Shape</classname> movements</title> <programlisting language="java">public class Shape { /** * Move by a given translation vector * @param xTrans Translation's x component * @param yTrans Translation's y component */ public void move(final int xTrans, final int yTrans) { x += xTrans; y += yTrans; } ...</programlisting> </figure> <figure xml:id="sda_inherit_fig_shapeMoveProblemSubclass"> <title>Fools are everywhere!</title> <programlisting language="java">public class Rectangle extends Shape { @Override public void move(int xTrans, int yTrans) { // I'm so dumb! ... }</programlisting> </figure> <figure xml:id="sda_inherit_fig_shapeMoveProblemSubclassSolution"> <title>Solution: <emphasis role="red">final</emphasis> prevents overriding</title> <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> <section xml:id="sd1_inherit_sect_abstractMethods"> <title>Abstract methods</title> <figure xml:id="sda_inherit_fig_subclassImplementGetArea"> <title>Calculating a shape's area</title> <informaltable border="0"> <tr> <td valign="top"><programlisting language="java">public class Rectangle extents Shape { /** * Calculate the area. * @return The rectangle's area */ public double getArea() { return width * height; } ...</programlisting></td> <td valign="top"><programlisting language="java">public class Circle extents Shape { /** * Calculate the area. * @return The circle's area */ public double getArea() { return PI * radius * radius; } ...</programlisting></td> </tr> </informaltable> </figure> <figure xml:id="sda_inherit_fig_shapePolymorphicAreaCall"> <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 linkends="sda_inherit_fig_shapePolymorphicAreaCall-2" xml:id="sda_inherit_fig_shapePolymorphicAreaCall-2-co"/>, 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>); <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> Rectangle at (1.0|-1.0), width= 2.0, height=3.0: <emphasis role="red">area = 6.0</emphasis></screen> <calloutlist role="slideExclude"> <callout arearefs="sda_inherit_fig_shapePolymorphicAreaCall-1-co" xml:id="sda_inherit_fig_shapePolymorphicAreaCall-1"> <para>An array of <classname>Shape</classname> references.</para> </callout> <callout arearefs="sda_inherit_fig_shapePolymorphicAreaCall-2-co" xml:id="sda_inherit_fig_shapePolymorphicAreaCall-2"> <para>A <classname>Rectangle</classname> <quote>is a</quote> <classname>Shape</classname> and likewise is <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 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> <figure xml:id="sda_inherit_fig_getAreaPolymorphicProblem"> <title>Problems:</title> <itemizedlist> <listitem> <para>No meaningful <methodname>getArea()</methodname> method in class <classname>Shape</classname> possible.</para> </listitem> <listitem> <para>Meaningful implementations exist both in subclass<classname> Rectangle</classname> and <classname>Circle</classname>.</para> </listitem> </itemizedlist> <para>Solution: Abstract method <methodname>getArea()</methodname> in superclass <classname>Shape</classname>.</para> </figure> <figure xml:id="sda_inherit_fig_implementAbstractGetArea"> <title><code language="java">abstract</code> method <methodname>getArea()</methodname></title> <informaltable border="0"> <colgroup width="25%"/> <colgroup width="25%"/> <colgroup width="25%"/> <colgroup width="25%"/> <tr> <td valign="top"/> <td colspan="2" valign="top"><programlisting language="java">abstract<co linkends="sda_inherit_fig_implementAbstractGetArea-1" xml:id="sda_inherit_fig_implementAbstractGetArea-1-co"/> public class Shape { /** * Calculate the shape's area. * @return The shape's area */ abstract<co linkends="sda_inherit_fig_implementAbstractGetArea-2" xml:id="sda_inherit_fig_implementAbstractGetArea-2-co"/> public double getArea()<co linkends="sda_inherit_fig_implementAbstractGetArea-3" xml:id="sda_inherit_fig_implementAbstractGetArea-3-co"/>; ...</programlisting></td> <td valign="top"/> </tr> <tr> <td colspan="2" valign="top"><programlisting language="java">public class Rectangle extends Shape { @Override<co linkends="sda_inherit_fig_implementAbstractGetArea-4" xml:id="sda_inherit_fig_implementAbstractGetArea-4-co"/> public double getArea() { return width * height; }...</programlisting></td> <td colspan="2" valign="top"><programlisting language="java">public class Circle ... { @Override<coref linkend="sda_inherit_fig_implementAbstractGetArea-4-co"/> public double getArea() { return Math.PI * radius * radius; } ...</programlisting></td> </tr> </informaltable> <calloutlist role="slideExclude"> <callout arearefs="sda_inherit_fig_implementAbstractGetArea-1-co" xml:id="sda_inherit_fig_implementAbstractGetArea-1"> <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 some concrete (= non-<code language="java">abstract</code>) subclass will either offer an implementation of <classname>getArea()</classname> or will have an intermediate parent class doing so.</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" xml:id="sda_inherit_fig_implementAbstractGetArea-3"> <para>An <code language="java">abstract</code> method must not have an implementing body <code language="java">{...}</code>.</para> </callout> <callout arearefs="sda_inherit_fig_implementAbstractGetArea-4-co" xml:id="sda_inherit_fig_implementAbstractGetArea-4"> <para>Both <classname>Rectangle</classname> and <classname>Circle</classname> are concrete (=non-<code language="java">abstract</code>) classes and are thus obliged to provide an implementation of <methodname>double getArea()</methodname>.</para> </callout> </calloutlist> </figure> <figure xml:id="sda_inherit_fig_shapeGetAreaAbstract"> <title><code language="java">abstract</code> method <methodname>getArea()</methodname></title> <mediaobject> <imageobject> <imagedata fileref="Fig/shapeGetAreaAbstract.multi.svg"/> </imageobject> </mediaobject> </figure> <figure xml:id="sda_inherit_fig_whatIsShapeAnyway"> <title>What's a <quote>shape</quote> anyway?</title> <mediaobject> <imageobject> <imagedata fileref="Fig/ghost.svg"/> </imageobject> </mediaobject> </figure> <figure xml:id="sd1_inherit_fig_noAbstractInstances"> <title>No instances of <code language="java">abstract</code> classes.</title> <programlisting language="none">final Shape s = new Shape(1., 2.); // <emphasis role="red">'Shape' is abstract; cannot be instantiated</emphasis></programlisting> </figure> <figure xml:id="sd1_inherit_fig_getAreaCompulsory"> <title>Mandatory <methodname>getArea()</methodname> implementation.</title> <programlisting language="none">// Error: <emphasis role="red">Class 'Circle' must either be declared abstract or</emphasis> // <emphasis role="red">implement abstract method 'getArea()' in 'Shape'</emphasis> public class Circle extends Shape { public Circle(double x,double y, double radius) { super(x, y); this.radius = radius; } private double radius; }</programlisting> </figure> <figure xml:id="sd1_inherit_fig_abstractFacts"> <title>Facts about <code language="java">abstract</code> fields, methods and classes.</title> <itemizedlist> <listitem> <para>A class containing an <code language="java">abstract</code> method must itself be declared <code language="java">abstract</code>.</para> </listitem> <listitem> <para><code language="java">abstract</code> classes are allowed to host non-<code language="java">abstract</code> methods.</para> </listitem> <listitem> <para>A class may be declared <code language="java">abstract</code> irrespective of purely containing non-<code language="java">abstract</code> methods.</para> </listitem> </itemizedlist> </figure> <section xml:id="sw1SectGeometryInherit"> <title>Geometry classes reconsidered</title> <para>Starting in <xref linkend="sd1_qanda_geometry_Rectangle"/> you implemented rectangle and circle related classes. You may have observed translation related parameters to be shape independent.</para> <para>Our <classname>Rectangle</classname> and <classname>Circle</classname> instances are being described by <code language="java">width</code>, <code language="java">height</code> and <code>radius</code>. Implementing a drawing application requires <emphasis>arbitrary</emphasis> objects to be moved from one position to another e.g.:</para> <figure xml:id="sd1FigFigureMove"> <title>Moving shapes</title> <mediaobject> <imageobject> <imagedata fileref="Fig/figureMove.svg"/> </imageobject> </mediaobject> </figure> <para>We might implement translation (move) related parameters and methods in both classes Rectangle and Circle independently. But since the underlying operation is indeed shape independent we choose a different approach using inheritance in the subsequent exercises.</para> <qandaset defaultlabel="qanda" xml:id="sd1QandaFigureBaseClass"> <title>Defining a <classname>Shape</classname> class hierarchy</title> <qandadiv> <qandaentry> <question> <para>Our two geometric primitives circle and rectangle will need a reference point (x,y) to define <methodname>move(...)</methodname> operations. We choose the center of gravity both for rectangles and circles:</para> <mediaobject> <imageobject> <imagedata fileref="Fig/figureCenter.svg"/> </imageobject> </mediaobject> <para>We thus need two additional parameters <property>x</property> and <property>y</property> representing an object's position. Consider the following inheritance diagram and implement the three <xref linkend="glo_Java"/> classes <classname>Shape</classname>, <classname>Circle</classname> and <classname>Rectangle</classname>:</para> <mediaobject> <imageobject> <imagedata fileref="Fig/qandaShapeBasic.svg"/> </imageobject> </mediaobject> <para>Create unit tests checking for correct implementation of the translation example from <xref linkend="sd1FigFigureMove"/> and the all other methods.</para> <para>Why is <methodname>move(...)</methodname> being defined returning an instance of class <classname>Shape</classname>?</para> <tip> <para>Think of multiple / combined operations.</para> </tip> </question> <answer> <annotation role="make"> <para role="eclipse">P/Sd1/Figure/BaseClass</para> </annotation> <para>Defining <methodname>move(...)</methodname> returning an instance of class <classname>Shape</classname> allows for operation chaining:</para> <programlisting language="java">final Circle c = new Circle(1., 2., 3.0); double p = c.move(1, 5).move(-3, 7).getPrimeter();</programlisting> </answer> </qandaentry> </qandadiv> </qandaset> <section xml:id="sd1SectFigureScale"> <title>Scaling shapes</title> <qandaset defaultlabel="qanda" xml:id="sd1QandaFigureScaling"> <qandadiv> <qandaentry> <question> <para>We want shapes to become scalable:</para> <mediaobject> <imageobject> <imagedata fileref="Fig/scale.svg"/> </imageobject> </mediaobject> <para>In the above example the rectangle is being shrunk to 50% of its original size whereas the circle's radius is being doubled. Add a corresponding <methodname>scale(...)</methodname> method to the inheritance hierarchy which allows for operation chaining as well.</para> <para>Provide appropriate unit tests.</para> </question> <answer> <annotation role="make"> <para role="eclipse">P/Sd1/Figure/Scale</para> </annotation> <para>This task is pretty much straightforward. Since scaling requires specific details (like radius or width and height) a <methodname>scale()</methodname> method cannot be implemented on top level of our inheritance hierarchy. We thus start by defining an abstract method in our class <classname>Shape</classname>:</para> <programlisting language="java">/** * * @param factor Scale the current shape by this value. * @return The current object. */ public abstract Shape scale(double factor);</programlisting> <para>This method has to be implemented in our two concrete classes <classname>Circle</classname> and <classname>Rectangle</classname>.</para> <para>Sensible unit tests may be based on the observation that:</para> <itemizedlist> <listitem> <para>A shape's perimeter grows linear with the scaling factor.</para> </listitem> <listitem> <para>A shape's area grows linear with the scaling factor's square.</para> </listitem> </itemizedlist> </answer> </qandaentry> </qandadiv> </qandaset> </section> <section xml:id="sd1SectFigureToString"> <title>Providing <methodname xlink:href="javaapi://Object#toString--">toString()</methodname> methods</title> <qandaset defaultlabel="qanda" xml:id="sd1QandaFigureToString"> <qandadiv> <qandaentry> <question> <para>Consider:</para> <programlisting language="java">final Circle c = new Circle(-2, -1, 3.5); final Rectangle r = new Rectangle(3, 1, 1.5, 4.4); System.out.println(c); System.out.println(r);</programlisting> <para>This creates the following output:</para> <screen>de.hdm_stuttgart.mi.sd1.shape.model.Circle@659e0bfd de.hdm_stuttgart.mi.sd1.shape.model.Rectangle@2a139a55</screen> <para>This result is due to the invocation of the <methodname xlink:href="javaapi://Object#toString--">toString()</methodname> method being defined in the <classname xlink:href="javaapi://Object">Object</classname> superclass. Override this method in <classname>Shape</classname>, <classname>Circle</classname> and <classname>Rectangle</classname> accordingly to get:</para> <screen>Circle (-2.0,-1.0), radius=3.5 Rectangle (3.0,1.0), width=1.5, height=4.4</screen> <para>Provide appropriate unit tests.</para> <tip> <para>You may access <methodname>Shape.toString()</methodname> from derived classes by using <code language="java">super()</code>.</para> </tip> </question> <answer> <annotation role="make"> <para role="eclipse">P/Sd1/Figure/ToString</para> </annotation> </answer> </qandaentry> </qandadiv> </qandaset> </section> </section> </section> <section xml:id="sd1_inherit_sect_protected"> <title><code language="java">protected</code> access</title> <figure xml:id="sda_inherit_fig_protectedCreationTime"> <title><code language="java">protected</code> access</title> <programlisting language="none"><emphasis role="red">package model</emphasis>; public abstract class Shape <co linkends="sda_inherit_fig_protectedCreationTime-1" xml:id="sda_inherit_fig_protectedCreationTime-1-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" xml:id="sda_inherit_fig_protectedCreationTime-3-co"/>extends Shape { static final Logger log = LogManager.getLogger(Rectangle.class); @Override public double getArea() { log.info("Rectangle creation time:" + <emphasis role="red">creationTime</emphasis> <co linkends="sda_inherit_fig_protectedCreationTime-4" xml:id="sda_inherit_fig_protectedCreationTime-4-co"/>); return width * height; } ... }</programlisting> <calloutlist role="slideExclude"> <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-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> <qandaset defaultlabel="qanda" xml:id="sd1_qanda_protectedPackagePrivate"> <title><code language="java">protected</code> vs. <quote>package private</quote></title> <qandadiv> <qandaentry> <question> <para>Implement <xref linkend="sda_inherit_fig_protectedCreationTime"/> in your IDE but exchanging <classname>Rectangle</classname> by <classname>Circle</classname> accordingly. Then execute <classname>Circle</classname>.<methodname>getArea()</methodname> and watch the logging outcome.</para> <para>Now apply the following two changes:</para> <orderedlist> <listitem> <para>Remove <code language="java">creationTime</code>'s <code language="java">protected</code> modifier.</para> </listitem> <listitem> <para>Move class <classname>Circle</classname> to package <package>model</package>.</para> </listitem> </orderedlist> <para>Are you still able to run your code? Explain the result.</para> </question> <answer> <para>Implementing class <classname>Circle</classname> is straightforward:</para> <programlisting language="none">public class Circle extends Shape { static final Logger log = LogManager.getLogger(Circle.class); @Override public double getArea() { log.info("Circle creation time:" + creationTime ); return Math.PI * radius * radius; } private double radius; }</programlisting> <para>Executing <code language="java">new Circle().getArea()</code> results in:</para> <screen>2018-01-03 08:31:18,811 INFO [main] sup.Circle (Circle.java:11) - Circle creation time:3340216708709</screen> <para>Removing <code language="java">protected</code> yields a compile time error:</para> <programlisting language="none">public class Circle extends Shape { static final Logger log = LogManager.getLogger(Circle.class); @Override public double getArea() { <emphasis role="red">// Error: 'creationTime' is not public in 'testprotect.model.Shape'. // Cannot be accessed from outside package</emphasis> log.info("Circle creation time:" + creationTime ); ...</programlisting> <para>Moving class <classname>Circle</classname> to package <package>model</package> resolves the issue: Having both classes <classname>Shape</classname> and <classname>Circle</classname> in a common package <package>model</package> implies <quote>package private</quote> access. Thus every method in <classname>Circle</classname> has full access to all fields and methods of <classname>Shape</classname>.</para> <note> <para>In a production environment this may or may not be desired and is thus a design choice.</para> </note> </answer> </qandaentry> </qandadiv> </qandaset> <qandaset defaultlabel="qanda" xml:id="sd1_qanda_protectedAccessProblem"> <title><code language="java">protected</code> access involving different instances</title> <qandadiv> <qandaentry> <question> <para>We reconsider class <classname>AlphaSub</classname> from <xref linkend="sd1_qanda_oracleAccessExample"/>:</para> <programlisting language="java">package package_two; import package_one.Alpha; public class AlphaSub extends Alpha { void dummy(/* Inherited */) { int v; v = attribPublic; v = attribProtected; v = <emphasis role="red">attribDefault</emphasis>; v = <emphasis role="red">attribPrivate</emphasis>; } }</programlisting> <para>If we try to access a different instance's <code language="java">attribProtected</code> we fail:</para> <programlisting language="java">package package_two; import package_one.Alpha; public class AlphaSub extends Alpha { void dummy(final Alpha a) { int v; ... v = a.<emphasis role="red">attribProtected</emphasis>; ... } }</programlisting> <para>Why is this access prohibited? Both the calling instance and the argument <code language="java">a</code> still belong to the <classname>Alpha</classname> / <classname>AlphaSum</classname> class hierarchy. Explain the different behavior.</para> </question> <answer> <para><code language="java">protected</code> inherited access grants an instance's subclass method access to a superclass attribute or method involving one common instance.</para> <para>The current use case differs: We have two (presumably different) instances one trying to access another's <code language="java">protected</code> attribute. This does not involve inheritance at all and thus fails.</para> </answer> </qandaentry> </qandadiv> </qandaset> </section> <section xml:id="sd1_sect_finalClass"> <title><code language="java">final</code> classes</title> <figure xml:id="sd1_inherit_fig_finalClass"> <title><code language="java">final</code> classes</title> <programlisting language="java">public final class Shape { ... } ------------------------- public class Rectangle extends Shape { // Error: final class cannot be extended ...</programlisting> </figure> <figure xml:id="sd1_inherit_fig_finalClassRatio"> <title><code language="java">final</code> classes rationale</title> <itemizedlist> <listitem> <para>Design decision.</para> </listitem> <listitem> <para>Slight performance gain.</para> </listitem> </itemizedlist> <blockquote> <note> <para>Prominent Example: <classname xlink:href="javaapi://String">java.lang.String</classname>.</para> </note> </blockquote> </figure> </section> <section xml:id="sd1_inherit_sect_instanceOf"> <title>The <code language="java" xlink:href="https://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.20.2">instanceof</code> operator</title> <figure xml:id="sd1_inherit_fig_defeatPolymorphism"> <title><quote>Defeating</quote> polymorphism</title> <informaltable border="0"> <colgroup width="68%"/> <colgroup width="32%"/> <tr> <td valign="top"><programlisting language="java">public static void main(String[] args) { 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 <link xlink:href="https://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.20.2">instanceof</link> Rectangle) { System.out.println("Type Rectangle"); } else if (s <link xlink:href="https://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.20.2">instanceof</link> Circle) { System.out.println("Type Circle"); } } }</programlisting></td> <td valign="top"><screen>Type Circle Type Rectangle</screen></td> </tr> </informaltable> </figure> <figure xml:id="sd1_inherit_fig_shapeDefineEqualsExamples"> <title>Defining <methodname>equals(...)</methodname>: Expectations</title> <programlisting language="java">Rectangle r1 = new Rectangle(1, 2, 5, 4), r2 = new Rectangle(1, 2, 1, 7), r3 = new Rectangle(1, 2, 5, 4); Circle c = new Circle(-2, 3, 5); System.out.print(r1.equals("Hi"));//<emphasis role="red">false</emphasis>: Differing classes Rectangle and String. System.out.print(r1.equals(r2)); //<emphasis role="red">false</emphasis>: Differing width and height. System.out.print(r3.equals(r1)); //<emphasis role="red">true</emphasis>: Two rectangles having identical // (x|y), width and height. System.out.print(r1.equals(c)); //<emphasis role="red">false</emphasis>: Differing classes Rectangle and Circle. System.out.print(c.equals(c)); //<emphasis role="red">true</emphasis>: Object equal to itself.</programlisting> </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> <programlisting language="java">public abstract class Shape { private double x, y; protected boolean equalCenter(final Shape o) { return Math.abs(o.x - x) + Math.abs(o.y - y) < 1.E-15; } ...</programlisting> </figure> <figure xml:id="sd1_inherit_fig_rectangleEquals"> <title>Implementing <classname>Rectangle</classname>.<methodname xlink:href="javaapi://Object#equals(java.lang.Object)">equals()</methodname></title> <programlisting language="java">public class Rectangle extends Shape { @Override public boolean equals(Object o) { if (o <link xlink:href="https://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.20.2">instanceof</link> Rectangle <emphasis role="red">r</emphasis>) { final Rectangle oRectangle = (Rectangle) o; // Cast is «legal» return super.equalCenter(<emphasis role="red">r</emphasis>) && Math.abs(<emphasis role="red">r</emphasis>.width- width) + Math.abs(<emphasis role="red">r</emphasis>.height- height) < 1.E-15; } return false; } ...</programlisting> <para>For <code language="java">o == null</code> the expression <code language="java">o <link xlink:href="https://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.20.2">instanceof</link> Rectangle</code> evaluates to <code language="java">false</code>.</para> </figure> <figure xml:id="sd1_inherit_fig_circleEquals"> <title>Implementing <classname>Circle</classname>.<methodname xlink:href="javaapi://Object#equals(java.lang.Object)">equals()</methodname></title> <programlisting language="java">public class Circle extends Shape { @Override public boolean equals(final Object o) { if (o <link xlink:href="https://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.20.2">instanceof</link> Circle <emphasis role="red">c</emphasis>){ return super.equalCenter(<emphasis role="red">c</emphasis>) && Math.abs(<emphasis role="red">c</emphasis>.radius - radius) < 1.E-15; } return false; } ...</programlisting> </figure> <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> <section xml:id="sd1_inherit_sect_Override"> <title>The <classname xlink:href="javaapi://Override">@Override</classname> annotation.</title> <figure xml:id="sd1_inherit_fig_overrideToString"> <title>Overriding Object.toString()</title> <programlisting language="java">public class Shape { double x, y; ... @Override // Promise: Subsequent method overrides Object.toString(); public String toString() { return "(" + x + "|" + y + ")"; } }</programlisting> </figure> <figure xml:id="sd1_inherit_fig_NotOverrideToString"> <title>@Override: Easy compile time error detection</title> <programlisting language="java">public class Shape { double x, y; ... @Override <emphasis role="red">// Error: method does not override a method from a supertype</emphasis> public String toString(int value) { return "(" + x + "|" + y + ")"; } }</programlisting> <para>Explanation: The given method does not override <methodname xlink:href="javaapi://Object#toString()">Object.toString()</methodname>.</para> </figure> </section> </chapter>