UNPKG

epubjs

Version:

Render ePub documents in the browser, across many devices

127 lines (124 loc) 19.1 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>Enter Generics</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="Enter Generics"><div class="titlepage"><div><div><h1 class="title"><a id="learnjava3-CHP-8-SECT-2"/>Enter Generics</h1></div></div></div><p><a id="idx10416" class="indexterm"/>Generics are an enhancement to the syntax of classes that allow us to specialize the class for a given type or set of types. A generic class requires one or more <span class="emphasis"><em>type parameters</em></span> wherever we refer to the class type and uses them to customize itself.</p><p>If you look at the source or Javadoc for the <code class="literal">List</code> class, for example, you’ll see it defined something like this:</p><a id="I_8_tt390"/><pre class="programlisting"> <code class="kd">public</code> <code class="kd">class</code> <code class="nc">List</code><code class="o">&lt;</code> <code class="n">E</code> <code class="o">&gt;</code> <code class="o">{</code> <code class="o">...</code> <code class="kd">public</code> <code class="kt">void</code> <code class="nf">add</code><code class="o">(</code> <code class="n">E</code> <code class="n">element</code> <code class="o">)</code> <code class="o">{</code> <code class="o">...</code> <code class="o">}</code> <code class="kd">public</code> <code class="n">E</code> <code class="nf">get</code><code class="o">(</code> <code class="kt">int</code> <code class="n">i</code> <code class="o">)</code> <code class="o">{</code> <code class="o">...</code> <code class="o">}</code> <code class="o">}</code></pre><p>The identifier <a id="I_indexterm8_id706979" class="indexterm"/><a id="I_indexterm8_id706985" class="indexterm"/><a id="I_indexterm8_id706990" class="indexterm"/><code class="literal">E</code> between the angle brackets (<code class="literal">&lt;&gt;</code>) is a <span class="emphasis"><em>type variable</em></span>. It indicates that the class <code class="literal">List</code> is generic and requires a Java type as an argument to make it complete. The name <code class="literal">E</code> is arbitrary, but there are conventions that we’ll see as we go on. In this case, the type variable <code class="literal">E</code> represents the type of elements we want to store in the list. The <code class="literal">List</code> class refers to the type variable within its body and methods as if it were a real type, to be substituted later. The type variable may be used to declare instance variables, arguments to methods, and the return type of methods. In this case, <code class="literal">E</code> is used as the type for the elements we’ll be adding via the <code class="literal">add()</code> method and the return type of the <code class="literal">get()</code> method. Let’s see how to use it.</p><p>The same angle bracket syntax supplies the type parameter when we want to use the <code class="literal">List</code> type:</p><a id="I_8_tt391"/><pre class="programlisting"> <code class="n">List</code><code class="o">&lt;</code><code class="n">String</code><code class="o">&gt;</code> <code class="n">listOfStrings</code><code class="o">;</code></pre><p>In this snippet, we declared a variable called <code class="literal">listOfStrings</code> using the generic type <code class="literal">List</code> with a type parameter of <code class="literal">String</code>. <code class="literal">String</code> refers to the <code class="literal">String</code> class, but we could have specialized <code class="literal">List</code> with any Java class type. For example:</p><a id="I_8_tt392"/><pre class="programlisting"> <code class="n">List</code><code class="o">&lt;</code><code class="n">Date</code><code class="o">&gt;</code> <code class="n">dates</code><code class="o">;</code> <code class="n">List</code><code class="o">&lt;</code><code class="n">java</code><code class="o">.</code><code class="na">math</code><code class="o">.</code><code class="na">BigDecimal</code><code class="o">&gt;</code> <code class="n">decimals</code><code class="o">;</code> <code class="n">List</code><code class="o">&lt;</code><code class="n">Foo</code><code class="o">&gt;</code> <code class="n">foos</code><code class="o">;</code></pre><p><a id="I_indexterm8_id707123" class="indexterm"/> <a id="I_indexterm8_id707130" class="indexterm"/>Completing the type by supplying its type parameter is called <span class="emphasis"><em>instantiating the type</em></span>. It is also sometimes called <span class="emphasis"><em>invoking the type</em></span>, by analogy with invoking a method and supplying its arguments. Whereas with a regular Java type, we simply refer to the type by name, a generic type must be instantiated with parameters wherever it is used.<sup>[<a id="learnjava3-CHP-8-FNOTE-1" href="#ftn.learnjava3-CHP-8-FNOTE-1" class="footnote">21</a>]</sup> Specifically, this means that we must instantiate the type everywhere types can appear as the declared type of a variable (as shown in this code snippet), as the type of a method argument, as the return type of a method, or in an object allocation expression using the <a id="I_indexterm8_id707158" class="indexterm"/><code class="literal">new</code> keyword.</p><p>Returning to our <code class="literal">listOfStrings</code>, what we have now is effectively a <code class="literal">List</code> in which the type <code class="literal">String</code> has been substituted for the type variable <code class="literal">E</code> in the class body:</p><a id="I_8_tt393"/><pre class="programlisting"> <code class="kd">public</code> <code class="kd">class</code> <code class="nc">List</code><code class="o">&lt;</code> <code class="n">String</code> <code class="o">&gt;</code> <code class="o">{</code> <code class="o">...</code> <code class="kd">public</code> <code class="kt">void</code> <code class="nf">add</code><code class="o">(</code> <code class="n">String</code> <code class="n">element</code> <code class="o">)</code> <code class="o">{</code> <code class="o">...</code> <code class="o">}</code> <code class="kd">public</code> <code class="n">String</code> <code class="nf">get</code><code class="o">(</code> <code class="kt">int</code> <code class="n">i</code> <code class="o">)</code> <code class="o">{</code> <code class="o">...</code> <code class="o">}</code> <code class="o">}</code></pre><p>We have specialized the <code class="literal">List</code> class to work with elements of type <code class="literal">String</code> and <span class="emphasis"><em>only</em></span> elements of type <code class="literal">String</code>. This method signature is no longer capable of accepting an arbitrary <code class="literal">Object</code> type.</p><p><code class="literal">List</code> is just an interface. To use the variable, we’ll need to create an instance of some actual implementation of <code class="literal">List</code>. As we did in our introduction, we’ll use <code class="literal">ArrayList</code>. As before, <code class="literal">ArrayList</code> is a class that implements the <code class="literal">List</code> interface, but in this case, both <code class="literal">List</code> and <code class="literal">ArrayList</code> are generic classes. As such, they require type parameters to instantiate them where they are used. Of course, we’ll create our <code class="literal">ArrayList</code> to hold <code class="literal">String</code> elements to match our <code class="literal">List</code> of <code class="literal">String</code>s:</p><a id="I_8_tt394"/><pre class="programlisting"> <code class="n">List</code><code class="o">&lt;</code><code class="n">String</code><code class="o">&gt;</code> <code class="n">listOfStrings</code> <code class="o">=</code> <code class="k">new</code> <code class="n">ArrayList</code><code class="o">&lt;</code><code class="n">String</code><code class="o">&gt;</code> <code class="n">List</code><code class="o">&lt;</code><code class="n">String</code><code class="o">&gt;</code> <code class="n">listOfStrings</code> <code class="o">=</code> <code class="k">new</code> <code class="n">ArrayList</code><code class="o">&lt;&gt;();</code> <code class="c1">// Or shorthand in Java 7.0</code> <code class="c1">// and later</code></pre><p>As always, the <a id="I_indexterm8_id707314" class="indexterm"/><code class="literal">new</code> keyword takes a Java type and parentheses with possible arguments for the class’s constructor. In this case, the type is <code class="literal">ArrayList&lt;String&gt;</code>—the generic <code class="literal">ArrayList</code> type instantiated with the <code class="literal">String</code> type.</p><p><a id="I_indexterm8_id707349" class="indexterm"/>Declaring variables as shown in the first line of the preceding example is a bit cumbersome because it requires us to type the generic parameter type twice (once on the left side in the variable type and once on the right in the initialing expression). And in complicated cases, the generic types can get very lengthy and nested within one another. In Java 7, the compiler is smart enough to infer the type of the initializing expression from the type of the variable to which you are assigning it. This is called <span class="emphasis"><em>generic type inference</em></span> and boils down to the fact that you can shorthand the right side of your variable declarations by leaving out the contents of the <code class="literal">&lt;&gt;</code> notation, as shown in the example’s second line.</p><p>We can now use our specialized <code class="literal">List</code> with strings. The compiler prevents us from even trying to put anything other than a <code class="literal">String</code> object (or a subtype of <code class="literal">String</code> if there were any) into the list and allows us to fetch them with the <code class="literal">get()</code> method without requiring any cast:</p><a id="I_8_tt395"/><pre class="programlisting"> <code class="n">List</code><code class="o">&lt;</code><code class="n">String</code><code class="o">&gt;</code> <code class="n">listOfStrings</code> <code class="o">=</code> <code class="k">new</code> <code class="n">ArrayList</code><code class="o">&lt;</code><code class="n">String</code><code class="o">&gt;();</code> <code class="n">listOfStrings</code><code class="o">.</code><code class="na">add</code><code class="o">(</code><code class="s">"eureka! "</code><code class="o">);</code> <code class="n">String</code> <code class="n">s</code> <code class="o">=</code> <code class="n">listOfStrings</code><code class="o">.</code><code class="na">get</code><code class="o">(</code><code class="mi">0</code><code class="o">);</code> <code class="c1">// "eureka! "</code> <code class="n">listOfStrings</code><code class="o">.</code><code class="na">add</code><code class="o">(</code> <code class="k">new</code> <code class="n">Date</code><code class="o">()</code> <code class="o">);</code> <code class="c1">// Compile-time Error!</code></pre><p>Let’s take another example from the Collections API. The <a id="I_indexterm8_id707415" class="indexterm"/><code class="literal">Map</code> interface provides a dictionary-like mapping that associates key objects with value objects. Keys and values do not have to be of the same type. The generic <code class="literal">Map</code> interface requires two type parameters: one for the key type and one for the value type. The Javadoc looks like this:</p><a id="I_8_tt396"/><pre class="programlisting"> <code class="kd">public</code> <code class="kd">class</code> <code class="nc">Map</code><code class="o">&lt;</code> <code class="n">K</code><code class="o">,</code> <code class="n">V</code> <code class="o">&gt;</code> <code class="o">{</code> <code class="o">...</code> <code class="kd">public</code> <code class="n">V</code> <code class="nf">put</code><code class="o">(</code> <code class="n">K</code> <code class="n">key</code><code class="o">,</code> <code class="n">V</code> <code class="n">value</code> <code class="o">)</code> <code class="o">{</code> <code class="o">...</code> <code class="o">}</code> <code class="c1">// returns any old value</code> <code class="kd">public</code> <code class="n">V</code> <code class="nf">get</code><code class="o">(</code> <code class="n">K</code> <code class="n">key</code> <code class="o">)</code> <code class="o">{</code> <code class="o">...</code> <code class="o">}</code> <code class="o">}</code></pre><p>We can make a <code class="literal">Map</code> that stores <code class="literal">Employee</code> objects by <code class="literal">Integer</code> “employee ID” numbers like this:</p><a id="I_8_tt397"/><pre class="programlisting"> <code class="n">Map</code><code class="o">&lt;</code> <code class="n">Integer</code><code class="o">,</code> <code class="n">Employee</code> <code class="o">&gt;</code> <code class="n">employees</code> <code class="o">=</code> <code class="k">new</code> <code class="n">HashMap</code><code class="o">&lt;</code> <code class="n">Integer</code><code class="o">,</code> <code class="n">Employee</code> <code class="o">&gt;();</code> <code class="n">Integer</code> <code class="n">bobsId</code> <code class="o">=</code> <code class="o">...;</code> <code class="n">Employee</code> <code class="n">bob</code> <code class="o">=</code> <code class="o">...;</code> <code class="n">employees</code><code class="o">.</code><code class="na">put</code><code class="o">(</code> <code class="n">bobsId</code><code class="o">,</code> <code class="n">bob</code> <code class="o">);</code> <code class="n">Employee</code> <code class="n">employee</code> <code class="o">=</code> <code class="n">employees</code><code class="o">.</code><code class="na">get</code><code class="o">(</code> <code class="n">bobsId</code> <code class="o">);</code></pre><p>Here, we used <code class="literal">HashMap</code>, which is a generic class that implements the <a id="I_indexterm8_id707482" class="indexterm"/><code class="literal">Map</code> interface, and instantiated both types with the type parameters <code class="literal">Integer</code> and <code class="literal">Employee</code>. The <code class="literal">Map</code> now works only with keys of type <code class="literal">Integer</code> and holds values of type <code class="literal">Employee</code>.</p><p>The reason we used <code class="literal">Integer</code> here to hold our number is that the type parameters to a generic class must be class types. We can’t parameterize a generic class with a primitive type, such as <code class="literal">int</code> or <code class="literal">boolean</code>. Fortunately, autoboxing of primitives in Java (see <a class="xref" href="ch05.html" title="Chapter 5. Objects in Java">Chapter 5</a>) makes it almost appear as if we can by allowing us to use primitive types as though they were wrapper types:</p><a id="I_8_tt398"/><pre class="programlisting"> <code class="n">employees</code><code class="o">.</code><code class="na">put</code><code class="o">(</code> <code class="mi">42</code><code class="o">,</code> <code class="n">bob</code> <code class="o">);</code> <code class="n">Employee</code> <code class="n">bob</code> <code class="o">=</code> <code class="n">employees</code><code class="o">.</code><code class="na">get</code><code class="o">(</code> <code class="mi">42</code> <code class="o">);</code></pre><p>Here, autoboxing converted the integer <code class="literal">42</code> to an <code class="literal">Integer</code> wrapper for us twice.</p><p>In <a class="xref" href="ch11.html" title="Chapter 11. Core Utilities">Chapter 11</a>, we’ll see that all of the Java collection classes and interfaces are generic. Furthermore, dozens of other APIs use generics to let you adapt them to specific types. We’ll talk about them as they occur throughout the book.</p><div class="sect2" title="Talking About Types"><div class="titlepage"><div><div><h2 class="title"><a id="learnjava3-CHP-8-SECT-2.1"/>Talking About Types</h2></div></div></div><p><a id="I_indexterm8_id707587" class="indexterm"/>Before we move on to more important things, we should say a few words about the way we describe a particular parameterization of a generic class. Because the most common and compelling case for generics is for container-like objects, it’s common to think in terms of a generic type “holding” a parameter type. In our example, we called our <code class="literal">List&lt;String&gt;</code> a “list of strings” because, sure enough, that’s what it was. Similarly, we might have called our employee map a “Map of employee IDs to Employee objects.” However, these descriptions focus a little more on what the classes <span class="emphasis"><em>do</em></span> than on the type itself. Take instead a single object container called <code class="literal">Trap&lt; E &gt;</code> that could be instantiated on an object of type <code class="literal">Mouse</code> or of type <code class="literal">Bear</code>; that is, <code class="literal">Trap&lt;Mouse&gt;</code> or <code class="literal">Trap&lt;Bear&gt;</code>. Our instinct is to call the new type a “mouse trap” or “bear trap.” Similarly, we could have thought of our list of strings as a new type: “string list” or our employee map as a new “integer employee object map” type. You may use whatever verbiage you prefer, but these latter descriptions focus more on the notion of the generic as a <span class="emphasis"><em>type</em></span> and may help a little bit later when we discuss how generic types are related in the type system. There we’ll see that the container terminology turns out to be a little counterintuitive.</p><p>In the following section, we’ll continue our discussion of generic types in Java from a different perspective. We’ve seen a little of what they can do; now we need to talk about how they do it.<a id="I_indexterm8_id707662" class="indexterm"/></p></div><div class="footnotes"><br/><hr/><div class="footnote"><p><sup>[<a id="ftn.learnjava3-CHP-8-FNOTE-1" href="#learnjava3-CHP-8-FNOTE-1" class="para">21</a>] </sup>That is, unless you want to use a generic type in a nongeneric way. We’ll talk about “raw” types later in this chapter.</p></div></div></div></body></html>