UNPKG

epubjs

Version:

Render ePub documents in the browser, across many devices

51 lines (50 loc) 7.24 kB
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"><head><title>Case Study: The Enum Class</title><link rel="stylesheet" href="core.css" type="text/css"/><meta name="generator" content="DocBook XSL Stylesheets V1.74.0"/></head><body><div class="sect1" title="Case Study: The Enum Class"><div class="titlepage"><div><div><h1 class="title"><a id="learnjava3-CHP-8-SECT-11"/>Case Study: The Enum Class</h1></div></div></div><p><a id="idx10397" class="indexterm"/> <a id="idx10406" class="indexterm"/>If you take a look at the definition of the <code class="literal">java.lang.Enum</code> class in Java 5 or later, you’ll see a rather bizarre-looking generic type declaration:</p><a id="I_8_tt475"/><pre class="programlisting"> <code class="n">Enum</code><code class="o">&lt;</code> <code class="n">E</code> <code class="kd">extends</code> <code class="n">Enum</code><code class="o">&lt;</code><code class="n">E</code><code class="o">&gt;</code> <code class="o">&gt;</code> <code class="o">{</code> <code class="o">...</code> <code class="o">}</code></pre><p>In trying to parse this, you may be hampered by two thoughts, which we’ll try to dispel right away. First, upon quick inspection this may appear to be recursive. The type variable <code class="literal">E</code> seems to be defined as something that’s not yet finished being defined. But it’s not really. We often have mathematical equations of the form <code class="literal">x = function( x )</code> and they are not recursive. What they really call for is a special value of <code class="literal">x</code> that satisfies the condition. Next, although it’s pretty clear that <code class="literal">E</code> is a subtype of some formulation of the generic <code class="literal">Enum</code> type, you may jump to the conclusion that <code class="literal">E</code> itself must be a generic type. Remember that concrete types can extend generics just as well as generics can.</p><p>With these thoughts in mind, let’s hunt for some arrangement that satisfies these bounds. Let’s focus only on the bound for a moment:</p><a id="I_8_tt476"/><pre class="programlisting"> <code class="n">E</code> <code class="kd">extends</code> <code class="n">Enum</code><code class="o">&lt;</code><code class="n">E</code><code class="o">&gt;</code></pre><p><code class="literal">E</code> is a subclass of some parameterization of <code class="literal">Enum</code> and, in particular, the parameterization of <code class="literal">Enum</code> on the subclass type itself. To say this again, what it does is to require that any invocations of the <code class="literal">Enum</code> type are by subclasses of some parameterization of the <code class="literal">Enum</code> type. And specifically, the parameterizations of the <code class="literal">Enum</code> type supply their own type as the type parameter to their parent, <code class="literal">Enum</code>. What kind of class satisfies this condition?</p><a id="I_8_tt477"/><pre class="programlisting"> <code class="kd">class</code> <code class="nc">Foo</code> <code class="kd">extends</code> <code class="n">Enum</code><code class="o">&lt;</code><code class="n">Foo</code><code class="o">&gt;</code> <code class="o">{</code> <code class="o">}</code></pre><p>This <code class="literal">Foo</code> class does. The declaration of <code class="literal">Foo</code>, in fact, reads just as the bound does. <code class="literal">Foo</code> is a plain concrete type that extends <code class="literal">Enum</code> parameterized by its own type.<sup>[<a id="learnjava3-CHP-8-FNOTE-3" href="#ftn.learnjava3-CHP-8-FNOTE-3" class="footnote">24</a>]</sup></p><p>What does this accomplish exactly? The first implication of this arrangement is that <code class="literal">Enum</code> can be instantiated only by subclasses of itself. Next, we have the condition that the <code class="literal">Enum</code> must be instantiated with the child type as its parameter type. This means that any methods of the parent <code class="literal">Enum</code> class that refer to the type variable <code class="literal">E</code> will now refer to the <span class="emphasis"><em>child</em></span> type. This peculiar bound has guaranteed that child types customize their parent with their own type. In fact, this is exactly what the <code class="literal">Enum</code> class in Java needs in order to make enums work. The <a id="I_indexterm8_id713642" class="indexterm"/><code class="literal">compareTo()</code> method of a Java enum refers to the type variable and is intended to be applicable only to other instances of the specific child <code class="literal">enum</code> type:</p><a id="I_8_tt478"/><pre class="programlisting"> <code class="kd">public</code> <code class="kt">int</code> <code class="nf">compareTo</code><code class="o">(</code> <code class="n">E</code> <code class="n">e</code> <code class="o">)</code> <code class="o">{</code> <code class="o">...</code> <code class="o">}</code></pre><p>For example, a <code class="literal">Dog</code> enum type should be able to compare only types of <code class="literal">Dog</code> and comparing a <code class="literal">Dog</code> with a <code class="literal">Cat</code> should produce a compile-time error. The bound accomplishes just that by adapting the <code class="literal">compareTo()</code> method to the <code class="literal">Dog</code> type:</p><a id="I_8_tt479"/><pre class="programlisting"> <code class="kd">class</code> <code class="nc">Dog</code> <code class="kd">extends</code> <code class="n">Enum</code><code class="o">&lt;</code><code class="n">Dog</code><code class="o">&gt;</code> <code class="o">{</code> <code class="o">...</code> <code class="o">}</code></pre><p>Normally, a nonfinal base class, having no way to know what children it may have in the future, could only refer to its own type as a general supertype for all of the children when it wants to work with others of its own kind. Methods of a nongeneric <code class="literal">Enum</code> class could only supply methods that work on any <code class="literal">Enum</code>. But through the magic of generics, we can effectively change the API of the class based on how it is invoked with parameters. In this case, we have arranged that all subclasses must supply themselves as the parameter for the base class, tailoring its methods to themselves and pushing the base type down a generation.<a id="I_indexterm8_id713732" class="indexterm"/><a id="I_indexterm8_id713739" class="indexterm"/></p><div class="footnotes"><br/><hr/><div class="footnote"><p><sup>[<a id="ftn.learnjava3-CHP-8-FNOTE-3" href="#learnjava3-CHP-8-FNOTE-3" class="para">24</a>] </sup>In real life, Java doesn’t let us extend the <code class="literal">Enum</code> type; that’s reserved for the <code class="literal">enum</code> keyword and the compiler. But the structure is as shown.</p></div></div></div></body></html>