﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-Lucifer-文章分类-Java</title><link>http://www.blogjava.net/luo1984guang/category/26494.html</link><description>天堂闪烁着神的光辉、回荡着天籁之音，一切那么的光明、和谐，平静、正义、安宁,然而这一切一切的完美却让我无法承受 .一个天籁之音也无法掩盖的声音在心中回荡：“释放吧，拒绝神的光辉，面对自己的阴影，聆听心中的悸动，我会让你看到真实，摧毁虚伪的完美吧，你会得到真实与自由。代价是成为叛逆的天使，恶魔的化身！” 我发出嘶鸣的嚎叫挥舞双翼远离天堂，让风将我圣洁的灵魂带入混沌的人间，投入暗无止境的地狱。悲鸣之声在地狱回荡：“宁在地狱称王，不在天堂为仆，我是风、火与血的凝结，我是将引导你的灵魂坠落的天使！”</description><language>zh-cn</language><lastBuildDate>Fri, 12 Oct 2007 19:00:51 GMT</lastBuildDate><pubDate>Fri, 12 Oct 2007 19:00:51 GMT</pubDate><ttl>60</ttl><item><title>了解泛型</title><link>http://www.blogjava.net/luo1984guang/articles/152163.html</link><dc:creator>lg</dc:creator><author>lg</author><pubDate>Thu, 11 Oct 2007 14:27:00 GMT</pubDate><guid>http://www.blogjava.net/luo1984guang/articles/152163.html</guid><wfw:comment>http://www.blogjava.net/luo1984guang/comments/152163.html</wfw:comment><comments>http://www.blogjava.net/luo1984guang/articles/152163.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/luo1984guang/comments/commentRss/152163.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/luo1984guang/services/trackbacks/152163.html</trackback:ping><description><![CDATA[<span style="font-size: 12pt;">
<span style="font-size: 36pt;"><span><span style="font-size: 36pt;"><span style="font-size: 24pt;"><span style="font-size: 18pt;"><span style="font-size: 14pt;"><span style="font-size: 12pt;"><span style="font-size: 10pt;"><span style="font-size: 8pt;">
<blockquote><br />
<span style="font-size: 18pt;"><span style="font-size: 10pt;"><span style="font-size: 12pt;"><span style="font-size: 10pt;"><span style="font-size: 18pt;"><span style="font-size: 10pt;"><span style="font-size: 12pt;"><span style="font-size: 8pt;"><span style="font-size: 18pt;"><span style="font-size: 10pt;"><span style="font-size: 12pt;"><span style="font-size: 10pt;"><span style="font-size: 18pt;"><span style="font-size: 10pt;"><span style="font-size: 12pt;"><span style="font-size: 10pt;">
JDK 5.0 中增加的泛型类型，是 Java 语言中类型安全的一次重要改进。但是，对于初次使用泛型类型的用户来说，泛型的某些方面看起来可能不容易明白，甚至非常奇怪。表面上看起来，无论语法还是应用的环境（比如容器类），泛型类型（或者泛型）都类似于 C++ 中的模板。但是这种相似性仅限于表面，Java 语言中的泛型基本上完全在编译器中实现，由编译器执行类型检查和类型推断，然后生成普通的非泛型的字节码。这种实现技术称为擦除（erasure）（编译器使用泛型类型信息保证类型安全，然后在生成字节码之前将其清除），这项技术有一些奇怪，并且有时会带来一些令人迷惑的后果。虽然范型是 Java 类走向类型安全的一大步，但是在学习使用泛型的过程中几乎肯定会遇到头痛（有时候让人无法忍受）的问题。</span></span></span></span><br />
</span></span></span></span></span></span></span></span></span></span></span></span><br />
<span style="font-size: 10pt;"><a name="1.0"></a><a style="width: 20px; height: 20px; text-indent: 20px; background-repeat: no-repeat; background-image: url(/CuteSoft_Client/CuteEditor/Load.ashx?type=image&amp;file=anchor.gif);" name="1.0"></a><a style="width: 20px; height: 20px; text-indent: 20px; background-repeat: no-repeat; background-image: url(/CuteSoft_Client/CuteEditor/Load.ashx?type=image&amp;file=anchor.gif);" name="1.0"></a><a style="width: 20px; height: 20px; text-indent: 20px; background-repeat: no-repeat; background-image: url(/CuteSoft_Client/CuteEditor/Load.ashx?type=image&amp;file=anchor.gif);" name="1.0"></a><a style="width: 20px; height: 20px; text-indent: 20px; background-repeat: no-repeat; background-image: url(/CuteSoft_Client/CuteEditor/Load.ashx?type=image&amp;file=anchor.gif);" name="1.0"></a><a style="width: 20px; height: 20px; text-indent: 20px; background-repeat: no-repeat; background-image: url(/CuteSoft_Client/CuteEditor/Load.ashx?type=image&amp;file=anchor.gif);" name="1.0"></a><a style="width: 20px; height: 20px; text-indent: 20px; background-repeat: no-repeat; background-image: url(/CuteSoft_Client/CuteEditor/Load.ashx?type=image&amp;file=anchor.gif);" name="1.0"></a><a style="width: 20px; height: 20px; text-indent: 20px; background-repeat: no-repeat; background-image: url(/CuteSoft_Client/CuteEditor/Load.ashx?type=image&amp;file=anchor.gif);" name="1.0"></a><a name="1.0"><strong>泛型不是协变的</strong><br />
</a>
<p>虽然将集合看作是数组的抽象会有所帮助，但是数组还有一些集合不具备的特殊性质。Java 语言中的数组是协变的（covariant），也就是说，如果 Integer 扩展了 Number（事实也是如此），那么不仅 Integer 是 Number，而且 Integer[] 也是 Number[]，在要求 Number[] 的地方完全可以传递或者赋予 Integer[]。（更正式地说，如果 Number 是 Integer 的超类型，那么 Number[] 也是 Integer[] 的超类型）。您也许认为这一原理同样适用于泛型类型 List&lt;Number&gt; 是 List&lt;Integer&gt; 的超类型，那么可以在需要 List&lt;Number&gt; 的地方传递 List&lt;Integer&gt;。不幸的是，情况并非如此。
</p>
<p>
不允许这样做有一个很充分的理由：这样做将破坏要提供的类型安全泛型。如果能够将 List&lt;Integer&gt; 赋给 List&lt;Number&gt;。那么下面的代码就允许将非 Integer 的内容放入 List&lt;Integer</p>
</span>
<p>
</p>
<table style="border-collapse: collapse;" bgcolor="#c8ebff" border="1" bordercolor="" cellpadding="2" cellspacing="2" height="101" width="526">
    <tbody>
        <tr>
            <td>&nbsp;
            <pre class="displaycode"><span style="font-size: 10pt;">List&lt;Integer&gt; li = new ArrayList&lt;Integer&gt;();<br />
            List&lt;Number&gt; ln = li; // illegal<br />
            ln.add(new Float(3.1415));</span></pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<span style="font-size: 10pt;">因为 <code>ln</code> 是 <code>List&lt;Number&gt;</code>，所以向其添加 <code>Float</code> 似乎是完全合法的。但是如果 <code>ln</code> 是 <code>li</code> 的别名，那么这就破坏了蕴含在 <code>li</code> 定义中的类型安全承诺 —— 它是一个整数列表，这就是泛型类型不能协变的原因。
<p><strong><a name="1.1">其他的协变问题</a></strong></p>
<p><a name="1.1">
数组能够协变而泛型不能协变的另一个后果是，不能实例化泛型类型的数组（<code>new List&lt;String&gt;[3]</code> 是不合法的），除非类型参数是一个未绑定的通配符（<code>new List&lt;?&gt;[3]</code> 是合法的）。让我们看看如果允许声明泛型类型数组会造成什么后果：</a></p>
</span>
<p><a style="width: 20px; height: 20px; text-indent: 20px; background-repeat: no-repeat; background-image: url(/CuteSoft_Client/CuteEditor/Load.ashx?type=image&amp;file=anchor.gif);" name="1.1"></a></p>
<p><a name="1.1">
<table bgcolor="#c8ebff" border="1" bordercolor="" cellpadding="2" cellspacing="2" height="187" width="579">
    <tbody>
        <tr>
            <td>&nbsp;
            <pre class="displaycode"><span style="font-size: 10pt;">List&lt;String&gt;[] lsa = new List&lt;String&gt;[10]; // illegal<br />
            Object[] oa = lsa;  // OK because List&lt;String&gt; is a subtype of Object<br />
            List&lt;Integer&gt; li = new ArrayList&lt;Integer&gt;();<br />
            li.add(new Integer(3));<br />
            oa[0] = li; <br />
            String s = lsa[0].get(0); </span></pre>
            </td>
        </tr>
    </tbody>
</table>
</a><img alt="" src="http://www.ibm.com/i/c.gif" height="1" width="10" /></p>
<p><span style="font-size: 10pt;">
最后一行将抛出 <code>ClassCastException</code>，因为这样将把 <code>List&lt;Integer&gt;</code> 填入本应是 <code>List&lt;String&gt;</code> 的位置。因为数组协变会破坏泛型的类型安全，所以不允许实例化泛型类型的数组（除非类型参数是未绑定的通配符，比如 <code>List&lt;?&gt;</code>）。</span></p>
<hr size="2" width="100%" />
<a style="width: 20px; height: 20px; text-indent: 20px; background-repeat: no-repeat; background-image: url(/CuteSoft_Client/CuteEditor/Load.ashx?type=image&amp;file=anchor.gif);" name="2.0"></a><a name="2.0"><span class="atitle"><strong></strong></span></a><strong><a name="2.0"><span class="atitle"><strong><span style="font-size: 10pt;">构造延迟</span></strong><br />
</span></a>
</strong><span style="font-size: 10pt;">
<p>
因为可以擦除功能，所以 <code>List&lt;Integer&gt;</code> 和 <code>List&lt;String&gt;</code> 是同一个类，编译器在编译 <code>List&lt;V&gt;</code> 时只生成一个类（和 C++ 不同）。因此，在编译 <code>List&lt;V&gt;</code> 类时，编译器不知道 <code>V</code> 所表示的类型，所以它就不能像知道类所表示的具体类型那样处理 <code>List&lt;V&gt;</code> 类定义中的类型参数（<code>List&lt;V&gt;</code> 中的 <code>V</code>）。
</p>
<p>
因为运行时不能区分 <code>List&lt;String&gt;</code> 和 <code>List&lt;Integer&gt;</code>（运行时都是 <code>List</code>），用泛型类型参数标识类型的变量的构造就成了问题。运行时缺乏类型信息，这给泛型容器类和希望创建保护性副本的泛型类提出了难题。
</p>
<p>
比如泛型类 <code>Foo</code>：</p>
</span>
<p>
</p>
<table bgcolor="#c8ebff" border="1" bordercolor="" cellpadding="2" cellspacing="2" height="120" width="524">
    <tbody>
        <tr>
            <td>&nbsp;
            <pre class="displaycode"><span style="font-size: 10pt;">class Foo&lt;T&gt; { <br />
            public void doSomething(T param) { ... }<br />
            }</span></pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<span style="font-size: 10pt;">假设 <code>doSomething()</code> 方法希望复制输入的 <code>param</code> 参数，会怎么样呢？没有多少选择。您可能希望按以下方式实现 <code>doSomething()</code>：</span>
<p>
</p>
<table bgcolor="#c8ebff" border="1" bordercolor="" cellpadding="2" cellspacing="2" height="120" width="523">
    <tbody>
        <tr>
            <td>&nbsp;
            <pre class="displaycode"><span style="font-size: 10pt;">public void doSomething(T param) { <br />
            T copy = new T(param);  // illegal<br />
            }</span></pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<p><span style="font-size: 10pt;">
<p>
但是您不能使用类型参数访问构造函数，因为在编译的时候还不知道要构造什么类，因此也就不知道使用什么构造函数。使用泛型不能表达&#8220;<code>T</code> 必须拥有一个拷贝构造函数（copy constructor）&#8221;（甚至一个无参数的构造函数）这类约束，因此不能使用泛型类型参数所表示的类的构造函数。
</p>
<p>
<code>clone()</code> 怎么样呢？假设在 <code>Foo</code> 的定义中，<code>T</code> 扩展了 <code>Cloneable</code>：</p>
</span></p>
<p>
</p>
<table bgcolor="#c8ebff" border="1" bordercolor="" cellpadding="2" cellspacing="2" height="158" width="519">
    <tbody>
        <tr>
            <td>&nbsp;
            <pre class="displaycode"><span style="font-size: 8pt;"><span style="font-size: 10pt;">class Foo&lt;T extends Cloneable&gt; { <br />
            public void doSomething(T param) {<br />
            T copy = (T) param.clone();  // illegal <br />
            }<br />
            }</span></span></pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<span style="font-size: 10pt;">不幸的是，仍然不能调用 <code>param.clone()</code>。为什么呢？因为 <code>clone()</code> 在 <code>Object</code> 中是保护访问的，调用 <code>clone()</code> 必须通过将 <code>clone()</code> 改写公共访问的类引用来完成。但是重新声明 <code>clone()</code> 为 public 并不知道 <code>T</code>，因此克隆也无济于事。</span>
<hr size="2" width="100%" />
<a style="width: 20px; height: 20px; text-indent: 20px; background-repeat: no-repeat; background-image: url(/CuteSoft_Client/CuteEditor/Load.ashx?type=image&amp;file=anchor.gif);" name="2.1"></a><a name="2.1"><span class="smalltitle"><strong></strong></span></a><strong><a name="2.1"><span class="smalltitle"><strong><span style="font-size: 10pt;">构造通配符引用</span></strong><br />
</span></a></strong><span style="font-size: 10pt;"><a name="2.1">
因此，不能复制在编译时根本不知道是什么类的类型引用。那么使用通配符类型怎么样？假设要创建类型为 <code>Set&lt;?&gt;</code> 的参数的保护性副本。您知道 <code>Set</code> 有一个拷贝构造函数。而且别人可能曾经告诉过您，如果不知道要设置的内容的类型，最好使用 <code>Set&lt;?&gt;</code> 代替原始类型的 <code>Set</code>，因为这种方法引起的未检查类型转换警告更少。于是，可以试着这样写：<br />
</a></span><a style="width: 20px; height: 20px; text-indent: 20px; background-repeat: no-repeat; background-image: url(/CuteSoft_Client/CuteEditor/Load.ashx?type=image&amp;file=anchor.gif);" name="2.1"></a><a name="2.1"><br />
<table bgcolor="#c8ebff" border="1" bordercolor="" cellpadding="2" cellspacing="2" height="158" width="522">
    <tbody>
        <tr>
            <td>&nbsp;
            <pre class="displaycode"><span style="font-size: 10pt;">class Foo {<br />
            public void doSomething(Set&lt;?&gt; set) {<br />
            Set&lt;?&gt; copy = new HashSet&lt;?&gt;(set);  // illegal<br />
            }<br />
            }</span></pre>
            </td>
        </tr>
    </tbody>
</table>
</a><br />
<p><span style="font-size: 10pt;">
不幸的是，您不能用通配符类型的参数调用泛型构造函数，即使知道存在这样的构造函数也不行。不过您可以这样做：</span></p>
<p>
</p>
<table bgcolor="#c8ebff" border="1" bordercolor="" cellpadding="2" cellspacing="2" height="158" width="520">
    <tbody>
        <tr>
            <td>&nbsp;
            <pre class="displaycode"><span style="font-size: 10pt;">class Foo {<br />
            public void doSomething(Set&lt;?&gt; set) {<br />
            Set&lt;?&gt; copy = new HashSet&lt;Object&gt;(set);  <br />
            }<br />
            }</span></pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<a style="width: 20px; height: 20px; text-indent: 20px; background-repeat: no-repeat; background-image: url(/CuteSoft_Client/CuteEditor/Load.ashx?type=image&amp;file=anchor.gif);" name="2.0"></a><strong><a style="width: 20px; height: 20px; text-indent: 20px; background-repeat: no-repeat; background-image: url(/CuteSoft_Client/CuteEditor/Load.ashx?type=image&amp;file=anchor.gif);" name="2.0"></a></strong>
<p><span style="font-size: 10pt;">
这种构造不那么直观，但它是类型安全的，而且可以像 <code>new HashSet&lt;?&gt;(set)</code> 那样工作。</span></p>
<hr size="2" width="100%" />
<strong><a style="width: 20px; height: 20px; text-indent: 20px; background-repeat: no-repeat; background-image: url(/CuteSoft_Client/CuteEditor/Load.ashx?type=image&amp;file=anchor.gif);" name="2.2"></a><strong><a style="width: 20px; height: 20px; text-indent: 20px; background-repeat: no-repeat; background-image: url(/CuteSoft_Client/CuteEditor/Load.ashx?type=image&amp;file=anchor.gif);" name="2.2"></a><strong><strong><a style="width: 20px; height: 20px; text-indent: 20px; background-repeat: no-repeat; background-image: url(/CuteSoft_Client/CuteEditor/Load.ashx?type=image&amp;file=anchor.gif);" name="2.2"></a><strong><strong><strong><strong><a style="width: 20px; height: 20px; text-indent: 20px; background-repeat: no-repeat; background-image: url(/CuteSoft_Client/CuteEditor/Load.ashx?type=image&amp;file=anchor.gif);" name="2.2"></a><strong><strong><strong><strong><strong><strong><strong><strong><a name="2.2"></a><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><a name="2.2"><span class="smalltitle"></span></a><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><a name="2.2"><span class="smalltitle"><span style="font-size: 10pt;"><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><a name="2.2"><span class="smalltitle">构造数组<br />
<br />
</span></a></strong></strong><a style="width: 20px; height: 20px; text-indent: 20px; background-repeat: no-repeat; background-image: url(/CuteSoft_Client/CuteEditor/Load.ashx?type=image&amp;file=anchor.gif);" name="2.2"></a></strong></strong><a style="width: 20px; height: 20px; text-indent: 20px; background-repeat: no-repeat; background-image: url(/CuteSoft_Client/CuteEditor/Load.ashx?type=image&amp;file=anchor.gif);" name="2.2"></a></strong></strong></strong></strong><a style="width: 20px; height: 20px; text-indent: 20px; background-repeat: no-repeat; background-image: url(/CuteSoft_Client/CuteEditor/Load.ashx?type=image&amp;file=anchor.gif);" name="2.2"></a></strong></strong></strong></strong></strong></strong></strong></strong><a style="width: 20px; height: 20px; text-indent: 20px; background-repeat: no-repeat; background-image: url(/CuteSoft_Client/CuteEditor/Load.ashx?type=image&amp;file=anchor.gif);" name="2.2"></a></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong><a name="2.2"></a></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong><a name="2.2"><span class="smalltitle"></span></a></span></span></a></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong><a name="2.2"><span class="smalltitle"><span style="font-size: 10pt;"><a name="2.2">
如何实现</a><a style="width: 20px; height: 20px; text-indent: 20px; background-repeat: no-repeat; background-image: url(/CuteSoft_Client/CuteEditor/Load.ashx?type=image&amp;file=anchor.gif);" name="2.2"></a><a name="2.2"> </a><a style="width: 20px; height: 20px; text-indent: 20px; background-repeat: no-repeat; background-image: url(/CuteSoft_Client/CuteEditor/Load.ashx?type=image&amp;file=anchor.gif);" name="2.2"></a><a name="2.2"><code>ArrayList&lt;V&gt;</code>？假设类 <code>ArrayList</code> 管理一个 <code>V</code> 数组，您可能希望用 <code>ArrayList&lt;V&gt;</code> 的构造函数创建一个 <code>V</code> 数组</a></span></span></a><a name="2.2">：<br />
</a><a style="width: 20px; height: 20px; text-indent: 20px; background-repeat: no-repeat; background-image: url(/CuteSoft_Client/CuteEditor/Load.ashx?type=image&amp;file=anchor.gif);" name="2.2"></a><a style="width: 20px; height: 20px; text-indent: 20px; background-repeat: no-repeat; background-image: url(/CuteSoft_Client/CuteEditor/Load.ashx?type=image&amp;file=anchor.gif);" name="2.2"></a><a style="width: 20px; height: 20px; text-indent: 20px; background-repeat: no-repeat; background-image: url(/CuteSoft_Client/CuteEditor/Load.ashx?type=image&amp;file=anchor.gif);" name="2.2"></a><a style="width: 20px; height: 20px; text-indent: 20px; background-repeat: no-repeat; background-image: url(/CuteSoft_Client/CuteEditor/Load.ashx?type=image&amp;file=anchor.gif);" name="2.2"></a><a style="width: 20px; height: 20px; text-indent: 20px; background-repeat: no-repeat; background-image: url(/CuteSoft_Client/CuteEditor/Load.ashx?type=image&amp;file=anchor.gif);" name="2.2"></a><a name="2.2"><br />
<table bgcolor="#c8ebff" border="1" bordercolor="" cellpadding="2" cellspacing="2" height="187" width="516">
    <tbody>
        <tr>
            <td>&nbsp;
            <pre class="displaycode"><span style="font-size: 10pt;">class ArrayList&lt;V&gt; {<br />
            private V[] backingArray;<br />
            public ArrayList() {<br />
            backingArray = new V[DEFAULT_SIZE]; // illegal<br />
            }<br />
            }</span></pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
</a>
<p><span style="font-size: 10pt;">
<p>
但是这段代码不能工作 —— 不能实例化用类型参数表示的类型数组。编译器不知道 <code>V</code> 到底表示什么类型，因此不能实例化 <code>V</code> 数组。
</p>
<p>
Collections 类通过一种别扭的方法绕过了这个问题，在 Collections 类编译时会产生类型未检查转换的警告。<code>ArrayList</code> 具体实现的构造函数如下：</p>
</span></p>
<table bgcolor="#c8ebff" border="1" bordercolor="" cellpadding="2" cellspacing="2" height="173" width="513">
    <tbody>
        <tr>
            <td>&nbsp;
            <pre class="displaycode"><span style="font-size: 10pt;">class ArrayList&lt;V&gt; {<br />
            private V[] backingArray;<br />
            public ArrayList() {<br />
            backingArray = (V[]) new Object[DEFAULT_SIZE]; <br />
            }<br />
            }</span></pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<a name="2.2"><span style="font-size: 10pt;">为何这些代码在访问 <code>backingArray</code> 时没有产生 <code>ArrayStoreException</code> 呢？无论如何，都不能将 <code>Object</code> 数组赋给 <code>String</code> 数组。因为泛型是通过擦除实现的，<code>backingArray</code> 的类型实际上就是 <code>Object[]</code>，因为 <code>Object</code> 代替了 <code>V</code>。这意味着：实际上这个类期望 <code>backingArray</code> 是一个 <code>Object</code> 数组，但是编译器要进行额外的类型检查，以确保它包含 <code>V</code> 类型的对象。所以这种方法很奏效，但是非常别扭，因此不值得效仿。<br />
还有一种方法就是声明 <code>backingArray</code> 为 <code>Object</code> 数组，并在使用它的各个地方强制将它转化为 <code>V[]</code>。仍然会看到类型未检查转换警告（与上一种方法一样），但是它使一些未明确的假设更清楚了（比如 <code>backingArray</code> 不应逃避 <code>ArrayList</code> 的实现）。</span><br />
</a><hr size="2" width="100%" />
<strong><a name="2.3"><span class="smalltitle"><span style="font-size: 10pt;"><strong></strong></span></span></a><strong><a name="2.3"><span class="smalltitle"><span style="font-size: 10pt;">其他方法</span><br />
</span></a></strong>
</strong><a name="2.3"><span class="smalltitle"><span style="font-size: 10pt;">
<p>
最好的办法是向构造函数传递类文字（<code>Foo.class</code>），这样，该实现就能在运行时知道 <code>T</code> 的值。不采用这种方法的原因在于向后兼容性 —— 新的泛型集合类不能与 Collections 框架以前的版本兼容。
</p>
<p>
下面的代码中 <code>ArrayList</code> 采用了以下方法：</p>
</span></span></a>
<p>
</p>
<table bgcolor="#c8ebff" border="1" bordercolor="" cellpadding="2" cellspacing="2" width="500">
    <tbody>
        <tr>
            <td>&nbsp;
            <pre class="displaycode"><span style="font-size: 10pt;">public class ArrayList&lt;V&gt; implements List&lt;V&gt; {<br />
            private V[] backingArray;<br />
            private Class&lt;V&gt; elementType;<br />
            public ArrayList(Class&lt;V&gt; elementType) {<br />
            this.elementType = elementType;<br />
            backingArray = (V[]) Array.newInstance(elementType, DEFAULT_LENGTH);<br />
            }<br />
            }</span></pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<span style="font-size: 10pt;">但是等一等！仍然有不妥的地方，调用 <code>Array.newInstance()</code> 时会引起未经检查的类型转换。为什么呢？同样是由于向后兼容性。<code>Array.newInstance()</code> 的签名是：</span>
<p>
</p>
<table bgcolor="#c8ebff" border="1" bordercolor="" cellpadding="2" cellspacing="2" width="500">
    <tbody>
        <tr>
            <td>&nbsp;
            <pre class="displaycode"><span style="font-size: 10pt;">public static Object newInstance(Class&lt;?&gt; componentType, int length)</span></pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<span style="font-size: 10pt;">而不是类型安全的：</span>
<p>
</p>
<table bgcolor="#c8ebff" border="1" bordercolor="" cellpadding="2" cellspacing="2" width="500">
    <tbody>
        <tr>
            <td>&nbsp;
            <pre class="displaycode"><span style="font-size: 10pt;">public static&lt;T&gt; T[] newInstance(Class&lt;T&gt; componentType, int length)</span></pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<p><span style="font-size: 10pt;">
<p>
为何 <code>Array</code> 用这种方式进行泛化呢？同样是为了保持向后兼容。要创建基本类型的数组，如 <code>int[]</code>，可以使用适当的包装器类中的 <code>TYPE</code> 字段调用 <code>Array.newInstance()</code>（对于 <code>int</code>，可以传递 <code>Integer.TYPE</code> 作为类文字）。用 <code>Class&lt;T&gt;</code> 参数而不是 <code>Class&lt;?&gt;</code> 泛化 <code>Array.newInstance()</code>，对于引用类型有更好的类型安全，但是就不能使用 <code>Array.newInstance()</code> 创建基本类型数组的实例了。也许将来会为引用类型提供新的 <code>newInstance()</code> 版本，这样就两者兼顾了。
</p>
<p>
在这里可以看到一种模式 —— 与泛型有关的很多问题或者折衷并非来自泛型本身，而是保持和已有代码兼容的要求带来的副作用。</p>
</span></p>
<hr size="2" width="100%" />
<p><strong><a name="3.0"><span class="atitle"><span style="font-size: 10pt;">
<p><strong></strong></p>
</span></span></a><strong><a name="3.0"><span class="atitle"><span style="font-size: 10pt;">泛化已有的类</span></span></a></strong></strong></p>
<a name="3.0"><span class="atitle"><span style="font-size: 10pt;">
<p>
在转化现有的库类来使用泛型方面没有多少技巧，但与平常的情况相同，向后兼容性不会凭空而来。我已经讨论了两个例子，其中向后兼容性限制了类库的泛化。
</p>
<p>
另一种不同的泛化方法可能不存在向后兼容问题，这就是 <code>Collections.toArray(Object[])</code>。传入 <code>toArray()</code> 的数组有两个目的 —— 如果集合足够小，那么可以将其内容直接放在提供的数组中。否则，利用反射（reflection）创建相同类型的新数组来接受结果。如果从头开始重写 Collections 框架，那么很可能传递给 <code>Collections.toArray()</code> 的参数不是一个数组，而是一个类文字：</p>
</span></span></a>
<p>
</p>
<table bgcolor="#c8ebff" border="1" bordercolor="" cellpadding="2" cellspacing="2" height="120" width="528">
    <tbody>
        <tr>
            <td>&nbsp;
            <pre class="displaycode"><span style="font-size: 10pt;">interface Collection&lt;E&gt; { <br />
            public T[] toArray(Class&lt;T super E&gt; elementClass);<br />
            }</span></pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<span style="font-size: 10pt;">
因为 Collections 框架作为良好类设计的例子被广泛效仿，但是它的设计受到向后兼容性约束，所以这些地方值得您注意，不要盲目效仿。
<p>
首先，常常被混淆的泛型 Collections API 的一个重要方面是 <code>containsAll()</code>、<code>removeAll()</code> 和 <code>retainAll()</code> 的签名。您可能认为 <code>remove()</code> 和 <code>removeAll()</code> 的签名应该是：</p>
</span>
<p>
</p>
<table bgcolor="#c8ebff" border="1" bordercolor="" cellpadding="2" cellspacing="2" width="500">
    <tbody>
        <tr>
            <td>&nbsp;
            <pre class="displaycode"><span style="font-size: 10pt;">interface Collection&lt;E&gt; { <br />
            public boolean remove(E e);  // not really<br />
            public void removeAll(Collection&lt;? extends E&gt; c);  // not really<br />
            }</span></pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<span style="font-size: 10pt;">但实际上却是：</span>
<p>
</p>
<table bgcolor="#c8ebff" border="1" bordercolor="" cellpadding="2" cellspacing="2" height="139" width="529">
    <tbody>
        <tr>
            <td>&nbsp;
            <pre class="displaycode"><span style="font-size: 10pt;">interface Collection&lt;E&gt; { <br />
            public boolean remove(Object o);  <br />
            public void removeAll(Collection&lt;?&gt; c);<br />
            }</span></pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<span style="font-size: 10pt;">为什么呢？答案同样是因为向后兼容性。<code>x.remove(o)</code> 的接口表明&#8220;如果 <code>o</code> 包含在 <code>x</code> 中，则删除它，否则什么也不做。&#8221;如果 <code>x</code> 是一个泛型集合，那么 <code>o</code> 不一定与 <code>x</code> 的类型参数兼容。如果 <code>removeAll()</code> 被泛化为只有类型兼容时才能调用（<code>Collection&lt;? extends E&gt;</code>），那么在泛化之前，合法的代码序列就会变得不合法，比如：</span>
<p>
</p>
<table bgcolor="#c8ebff" border="1" bordercolor="" cellpadding="2" cellspacing="2" height="158" width="524">
    <tbody>
        <tr>
            <td>&nbsp;
            <pre class="displaycode"><span style="font-size: 10pt;">// a collection of Integers<br />
            Collection c = new HashSet();<br />
            // a collection of Objects<br />
            Collection r = new HashSet();<br />
            c.removeAll(r);</span></pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<p><span style="font-size: 10pt;">
<p>
如果上述片段用直观的方法泛化（将 <code>c</code> 设为 <code>Collection&lt;Integer&gt;</code>，<code>r</code> 设为 <code>Collection&lt;Object&gt;</code>），如果 <code>removeAll()</code> 的签名要求其参数为 <code>Collection&lt;? extends E&gt;</code> 而不是 no-op，那么就无法编译上面的代码。泛型类库的一个主要目标就是不打破或者改变已有代码的语义，因此，必须用比从头重新设计泛型所使用类型约束更弱的类型约束来定义 <code>remove()</code>、<code>removeAll()</code>、<code>retainAll()</code> 和 <code>containsAll()</code>。
</p>
<p>
在泛型之前设计的类可能阻碍了&#8220;显然的&#8221;泛型化方法。这种情况下就要像上例这样进行折衷，但是如果从头设计新的泛型类，理解 Java 类库中的哪些东西是向后兼容的结果很有意义，这样可以避免不适当的模仿。 </p>
</span></p>
<hr size="2" width="100%" />
<p><strong><a name="4.0"><span class="atitle"><span style="font-size: 10pt;">
<p><strong></strong></p>
</span></span></a><strong><a name="4.0"><span class="atitle"><span style="font-size: 10pt;">擦除的实现</span></span></a></strong></strong></p>
<a name="4.0"><span class="atitle"><span style="font-size: 10pt;">
<p><span style="font-size: 10pt;">
<p>
因为泛型基本上都是在 Java
编译器中而不是运行库中实现的，所以在生成字节码的时候，差不多所有关于泛型类型的类型信息都被&#8220;擦掉&#8221;了。换句话说，编译器生成的代码与您手工编写的不
用泛型、检查程序的类型安全后进行强制类型转换所得到的代码基本相同。与 C++ 不同，<code>List&lt;Integer&gt;</code> 和 <code>List&lt;String&gt;</code> 是同一个类（虽然是不同的类型但都是 <code>List&lt;?&gt;</code> 的子类型，与以前的版本相比，在 JDK 5.0 中这是一个更重要的区别）。
</p>
<p>
擦除意味着一个类不能同时实现 <code>Comparable&lt;String&gt;</code> 和 <code>Comparable&lt;Number&gt;</code>，因为事实上两者都在同一个接口中，指定同一个 <code>compareTo()</code> 方法。声明 <code>DecimalString</code> 类以便与 <code>String</code> 与 <code>Number</code> 比较似乎是明智的，但对于 Java 编译器来说，这相当于对同一个方法进行了两次声明：</p>
</span></p>
</span></span></a><strong><a style="width: 20px; height: 20px; text-indent: 20px; background-repeat: no-repeat; background-image: url(/CuteSoft_Client/CuteEditor/Load.ashx?type=image&amp;file=anchor.gif);" name="4.0"></a></strong>
<p>
</p>
<span style="font-size: 10pt;"><span style="font-size: 10pt;">
<table bgcolor="#c8ebff" border="1" bordercolor="" cellpadding="2" cellspacing="2" height="90" width="492">
    <tbody>
        <tr>
            <td>&nbsp;
            <pre class="displaycode"><span style="font-size: 24pt;"><span style="font-size: 18pt;"><span style="font-size: 14pt;"><span style="font-size: 12pt;"><span style="font-size: 10pt;"><span style="font-size: 8pt;"><span style="font-size: 10pt;">public class DecimalString implements Comparable&lt;Number&gt;, Comparable&lt;String&gt; { <br />
            &nbsp; ... <br />
            } </span></span></span></span></span></span></span></pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
</span></span><span style="font-size: 10pt;">擦除的另一个后果是，对泛型类型参数是用强制类型转换或者 <code>instanceof</code> 毫无意义。下面的代码完全不会改善代码的类型安全性：</span>
<p>
</p>
<table bgcolor="#c8ebff" border="1" bordercolor="" cellpadding="2" cellspacing="2" height="82" width="544">
    <tbody>
        <tr>
            <td>&nbsp;
            <pre class="displaycode"><span style="font-size: 10pt;">public &lt;T&gt; T naiveCast(T t, Object o) { return (T) o; }</span></pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<p><span style="font-size: 10pt;">
<p>
编译器仅仅发出一个类型未检查转换警告，因为它不知道这种转换是否安全。<code>naiveCast()</code> 方法实际上根本不作任何转换，<code>T</code> 直接被替换为 <code>Object</code>，与期望的相反，传入的对象被强制转换为 <code>Object</code>。
</p>
<p>
擦除也是造成上述构造问题的原因，即不能创建泛型类型的对象，因为编译器不知道要调用什么构造函数。如果泛型类需要构造用泛型类型参数来指定类型的对象，那么构造函数应该接受类文字（<code>Foo.class</code>）并将它们保存起来，以便通过反射创建实例。 </p>
</span></p>
<hr size="2" width="100%" />
<p><strong><a name="5.0"><span class="atitle"><span style="font-size: 10pt;">
<p><strong></strong></p>
</span></span></a><strong><a name="5.0"><span class="atitle"><span style="font-size: 10pt;">结束语</span></span></a></strong></strong></p>
<a name="5.0"><span class="atitle"><span style="font-size: 10pt;">
<p>
泛型是 Java
语言走向类型安全的一大步，但是泛型设施的设计和类库的泛化并非未经过妥协。扩展虚拟机指令集来支持泛型被认为是无法接受的，因为这会为 Java
厂商升级其 JVM 造成难以逾越的障碍。因此采用了可以完全在编译器中实现的擦除方法。类似地，在泛型 Java
类库时，保持向后兼容也为类库的泛化方式设置了很多限制，产生了一些混乱的、令人沮丧的结构（如 <code>Array.newInstance()</code>）。这并非泛型本身的问题，而是与语言的演化与兼容有关。但这些也使得泛型学习和应用起来更让人迷惑，更加困难。（摘录自IBM中国）</p>
</span></span></a>
<p>&nbsp;</p>
<p>
</p>
<p><br />
</p>
<p>
</p>
<p><br />
</p>
<p>
</p>
<p>
</p>
<p><br />
</p>
<p><br />
</p>
<a name="2.3"><br />
</a><strong><a style="width: 20px; height: 20px; text-indent: 20px; background-repeat: no-repeat; background-image: url(/CuteSoft_Client/CuteEditor/Load.ashx?type=image&amp;file=anchor.gif);" name="2.3"></a></strong><a style="width: 20px; height: 20px; text-indent: 20px; background-repeat: no-repeat; background-image: url(/CuteSoft_Client/CuteEditor/Load.ashx?type=image&amp;file=anchor.gif);" name="2.2"></a><strong><a style="width: 20px; height: 20px; text-indent: 20px; background-repeat: no-repeat; background-image: url(/CuteSoft_Client/CuteEditor/Load.ashx?type=image&amp;file=anchor.gif);" name="2.2"></a></strong>
<p><br />
</p>
<p><strong><a style="width: 20px; height: 20px; text-indent: 20px; background-repeat: no-repeat; background-image: url(/CuteSoft_Client/CuteEditor/Load.ashx?type=image&amp;file=anchor.gif);" name="2.0"></a></strong>
</p>
<p><strong><a style="width: 20px; height: 20px; text-indent: 20px; background-repeat: no-repeat; background-image: url(/CuteSoft_Client/CuteEditor/Load.ashx?type=image&amp;file=anchor.gif);" name="1.1"></a></strong><a style="width: 20px; height: 20px; text-indent: 20px; background-repeat: no-repeat; background-image: url(/CuteSoft_Client/CuteEditor/Load.ashx?type=image&amp;file=anchor.gif);" name="1.1"></a></p>
<a name="1.0"><br />
&nbsp;
</a><br />
</blockquote><!--start RESERVED FOR FUTURE USE INCLUDE FILES--><!-- include java script once we verify teams wants to use this and it will work on dbcs and cyrillic characters -->
<!--end RESERVED FOR FUTURE USE INCLUDE FILES-->
</span></span></span></span></span></span></span></span></span>
</span>
<img src ="http://www.blogjava.net/luo1984guang/aggbug/152163.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/luo1984guang/" target="_blank">lg</a> 2007-10-11 22:27 <a href="http://www.blogjava.net/luo1984guang/articles/152163.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>