|
目录
泛型 1. 基本概念
泛型提供了一种编译时类型安全检测机制,允许程序员在编译时检测非法类型。
泛型的本质是它们是参数化类型,即被操作的数据类型被指定为参数。
2. 通用方法
传入的只能是引用类型,不能是基本类型,
3. 静态泛型方法
4.泛型类和泛型方法
5. 泛型的类型擦除和反射
只能在运行时获取当前类文件中包含泛型信息的泛型类型,而不能在运行时动态获取泛型引用的类型。实际上,所谓泛型类型擦除,是指在编译时完成类型检查后,将一个特定的泛型引用擦除到 Object 中动态泛目录,并在运行时丢失它给出的类型信息。例如,一个真正不可擦除的泛型应该能够轻松地执行以下操作:
<p><pre> <code class="prism language-java"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">Test</span><span class="token generics"><span class="token punctuation"><</span><span class="token class-name">T</span><span class="token punctuation">></span></span> <span class="token punctuation">{</span>
<span class="token keyword">public</span> <span class="token class-name">T</span><span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token function">getArray</span><span class="token punctuation">(</span><span class="token keyword">int</span> length<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token class-name">Class</span><span class="token generics"><span class="token punctuation"><</span><span class="token class-name">T</span><span class="token punctuation">></span></span> clazz <span class="token operator">=</span> <span class="token class-name">T</span><span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">;</span>
<span class="token keyword">return</span> <span class="token punctuation">(</span><span class="token class-name">T</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token class-name">Array</span><span class="token punctuation">.</span><span class="token function">newInstance</span><span class="token punctuation">(</span>clazz<span class="token punctuation">,</span> length<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre></p>
上面代码中,假设泛型信息没有被擦除,我们在任意位置新建的Test实例都会保存自己的“T”类型信息,那么getArray方法就可以获取到实际的T类信息。类型擦除后,上述代码中并没有方法在getArray方法内部获取T的类型信息,这是擦除后的实际效果。我们所说的可以通过反射获得的泛型信息,必须是一个特定的泛型类型动态泛目录,其中一个类被用作成员变量、方法返回值等。例如:
<p><pre> <code class="prism language-java"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">Test</span><span class="token generics"><span class="token punctuation"><</span><span class="token class-name">T</span><span class="token punctuation">></span></span> <span class="token punctuation">{</span>
<span class="token keyword">private</span> <span class="token class-name">Test</span><span class="token generics"><span class="token punctuation"><</span><span class="token class-name">Integer</span><span class="token punctuation">></span></span> test<span class="token punctuation">;</span>
<span class="token keyword">private</span> <span class="token class-name">T</span> item<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre></p>
在上面的代码中,我们可以通过反射获取成员test的Integer泛型信息,但无法获取item的实际类型。
查看OpenJDK 8的相关源码,原则上示例中的测试成员在编译的时候会将Integer信息编译成类字节码,这样反射系统就可以获取到这个信息,如下图所示:
我们可以看到,其实test的通用信息是直接编译成字节码的。
该方法的本质操作是从加载的类信息中获取fieldDescriptor,从而生成Field对象的oop,将类的字段信息注入其中,返回给Java端的调用方法。回顾类中生成fieldDescriptor的代码,我们可以发现,其实JVM在加载字节码的时候,是把解析出来的通用信息保存到字节码中的。也就是说,在类加载阶段,JVM保存了写入字节码的通用信息。我们在反射的时候,反射系统自然可以获取到信息,这样就可以通过getGenericType()获取Type信息,从而解析出泛型类型。
豪侠泛目录站群程序,专业泛目录,站群,二级目录,泛站群程序! |
|