请选择 进入手机版 | 继续访问电脑版
查看: 140|回复: 0

Java开发:编译时类型平安检测机制(一)

[复制链接]

132

主题

134

帖子

713

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
713
发表于 2022-10-30 01:58:31 | 显示全部楼层 |阅读模式
目录

泛型 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信息,从而解析出泛型类型。

豪侠泛目录站群程序,专业泛目录,站群,二级目录,泛站群程序!
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

快速回复 返回顶部 返回列表