当前位置: 首页 > news >正文

网站建设制作设计营销 中山深圳货拉拉

网站建设制作设计营销 中山,深圳货拉拉,资兴市网站建设服务商,wordpress网站导航模板文章目录前序1. 泛型1.1 泛型方法1.2 泛型类1.3 泛型接口2. 泛型的基本原理3. 小结前序 泛型是 Java 开发中常用的技术,了解泛型的几种形式和实现泛型的基本原理,有助于写出更优质的代码。本文总结了 Java 泛型的三种形式以及泛型实现原理。 1. 泛型 …

文章目录

  • 前序
  • 1. 泛型
    • 1.1 泛型方法
    • 1.2 泛型类
    • 1.3 泛型接口
  • 2. 泛型的基本原理
  • 3. 小结

前序

泛型是 Java 开发中常用的技术,了解泛型的几种形式和实现泛型的基本原理,有助于写出更优质的代码。本文总结了 Java 泛型的三种形式以及泛型实现原理。

1. 泛型

泛型的本质是对类型进行参数化,在代码逻辑不关注具体的数据类型时使用。例如:实现一个通用的排序算法,此时关注的是算法本身,而非排序的对象的类型。

1.1 泛型方法

如下定义了一个泛型方法, 声明了一个类型变量,它可以应用于参数,返回值,和方法内的代码逻辑。

class GenericMethod{public <T> T[] sort(T[] elements){return elements;}
}

1.2 泛型类

与泛型方法类似,泛型类也需要声明类型变量,只不过位置放在了类名后面,作用的范围包括了当前中的成员变量类型,方法参数类型,方法返回类型,以及方法内的代码中。

子类继承泛型类时或者实例化泛型类的对象时,需要指定具体的参数类型或者声明一个参数变量。如下,SubGenericClass 继承了泛型类 GenericClass,其中类型变量 ID 的值为 Integer,同时子类声明了另一个类型变量 E,并将E 填入了父类声明的 T 中。

class GenericClass<ID, T>{}class SubGenericClass<T> extends GenericClass<Integer, T>{}

1.3 泛型接口

泛型接口与泛型类类似,也需要在接口名后面声明类型变量,作用于接口中的抽象方法返回类型和参数类型。子类在实现泛型接口时需要填入具体的数据类型或者填入子类声明的类型变量。

interface GenericInterface<T> {T append(T seg);
}

2. 泛型的基本原理

泛型本质是将数据类型参数化,它通过擦除的方式来实现。声明了泛型的 .java 源代码,在编译生成 .class 文件之后,泛型相关的信息就消失了。可以认为,源代码中泛型相关的信息,就是提供给编译器用的。泛型信息对 Java 编译器可以见,对 Java 虚拟机不可见。

Java 编译器通过如下方式实现擦除:

  • 用 Object 或者界定类型替代泛型,产生的字节码中只包含了原始的类,接口和方法;
  • 在恰当的位置插入强制转换代码来确保类型安全;
  • 在继承了泛型类或接口的类中插入桥接方法来保留多态性。

Java 官方文档原文

Replace all type parameters in generic types with their bounds or
Object if the type parameters are unbounded. The produced bytecode,
therefore, contains only ordinary classes, interfaces, and methods.
Insert type casts if necessary to preserve type safety. Generate
bridge methods to preserve polymorphism in extended generic types.

下面通过具体代码来说明 Java 中的类型擦除。

实验原理:先用 javac 将 .java 文件编译成 .class 文件,再使用反编译工具 jad 将 .class 文件反编成回 Java 代码,反编译出来的 Java 代码内容反映的即为 .class 文件中的信息。

如下源代码,定义 User 类,实现了 Comparable 接口,类型参数填入 User,实现 compareTo 方法。

class User implements Comparable<User> {String name;public int compareTo(User other){return this.name.compareTo(other.name);}
}

JDK 中 Comparable 接口源码内容如下:

package java.lang;
public interface Comparable<T>{int compareTo(T o);
}

我们首先反编译它的接口,Comparable 接口的字节码文件,可以在 $JRE_HOME/lib/rt.jar 中找到,将它复制到某个目录。使用 jad.exe(需要另外安装)反编译这个 Comparable.class 文件。

$ jad Comparable.class

反编译出来的内容放在 Comparable.jad 文件中,文件内容如下:

// Decompiled by Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov.
// Jad home page: http://www.kpdus.com/jad.html
// Decompiler options: packimports(3)
// Source File Name:   Comparable.javapackage java.lang;// Referenced classes of package java.lang:
//            Objectpublic interface Comparable
{public abstract int compareTo(Object obj);
}

对比源代码 Comparable.java 和反编译代码 Comparable.jad 的内容不难发现,反编译之后的内容中已经没有了类型变量 T 。compareTo 方法中的参数类型 T 也被替换成了 Object。这就符合上面提到的第 1 条擦除原则。这里演示的是用 Object 替换类型参数,使用界定类型替换类型参数的例子可以反编译一下 Collections.class 试试,里面使用了大量的泛型。

使用 javac.exe 将 User.java 编译成 .class 文件,然后使用 jad 将 .class 文件反编译成 Java 代码。

$ javac User.java
$ jad User.class

User.jad 文件内容如下:

// Decompiled by Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov.
// Jad home page: http://www.kpdus.com/jad.html
// Decompiler options: packimports(3)
// Source File Name:   User.javaclass Userimplements Comparable
{User(){}public int compareTo(User user){return name.compareTo(user.name);}// 桥接方法public volatile int compareTo(Object obj){return compareTo((User)obj);}String name;
}

对比编辑的源代码 User.java 和反编译出来的代码 User.jad,容易发现:类型参数没有了,多了一个无参构造方法,多了一个 compareTo(Object obj) 方法,这个就是桥接方法,还可以发现参数 obj 被强转成 User 再传入 compareTo(User user) 方法。通过这些内容可以看到擦除规则 2 和规则 3 的实现方式。

强转规则比较好理解,因为泛型被替换成了 Object,要调用具体类型的方法或者成员变量,当然需要先强转成具体类型才能使用。那么插入的桥接方法该如何理解呢?

如果我们只按照下面方式去使用 User 类,这样确实不需要参数类型为 Object 的桥接方法。

User user = new User();
User other = new User();
user.comparetTo(other);

但是,Java 中的多态特性允许我们使用一个父类或者接口的引用指向一个子类对象。

Comparable<User> user = new User();

而按照 Object 替换泛型参数原则,Comparable 接口中只有 compareTo(Object) 方法,假设没有桥接方法,显然如下代码是不能运行的。所以 Java 编译器需要为子类(泛型类的子类或泛型接口的实现类)中使用了泛型的方法额外生成一个桥接方法,通过这个方法来保证 Java 中的多态特性。

Comparable<User> user = new User();
Object other = new User();
user.compareTo(other);

而普通类中的泛型方法在进行类型擦除时不会产生桥接方法。例如:

class Dog{<T> void eat(T[] food){}
}

类型擦除之后变成了:

class Dog
{Dog(){}void eat(Object aobj[]){}
}

3. 小结

Java 中的泛型有 3 种形式,泛型方法,泛型类,泛型接口。Java 通过在编译时类型擦除的方式来实现泛型。擦除时使用 Object 或者界定类型替代泛型,同时在要调用具体类型方法或者成员变量的时候插入强转代码,为了保证多态特性,Java 编译器还会为泛型类的子类生成桥接方法。类型信息在编译阶段被擦除之后,程序在运行期间无法获取类型参数所对应的具体类型。

http://www.khdw.cn/news/25840.html

相关文章:

  • 廊坊怎么做网站网络推广整合平台
  • 济南网站改版html网页制作网站
  • 广东省建站公司宁波seo行者seo09
  • 企业网站建设参考资料微信广告
  • 网站标题的重要性微信营销怎么做
  • 网站建设基础大纲文案想要推广网页正式版
  • 企业网站模板下载哪家好广告网站策划方案
  • 企业不开了网站备案吗seo的课谁讲的好
  • 卓越 网站建设 深圳西乡东莞网站建设优化
  • 中国建设银行网站缴费系统做互联网项目怎么推广
  • 网站的pdf目录怎么做的网页设计工资一般多少
  • 手机网站开发技术网络推广营销技巧
  • 深圳开发网站建设网络平台推广具体是怎么推广
  • 网站信息化建设方案天津优化公司
  • WordPress固定链接跳转seo是啥
  • 专业网站建设开发甲马营seo网站优化的
  • 网站制作费会计分录怎么做营销型网站建设流程
  • 天津营销网站建设联系方式网络营销成功案例介绍
  • 做网站的图片房产成人用品网店进货渠道
  • 做网站 模板网站开发外包
  • 全国装饰公司最新排行榜长沙谷歌seo
  • 网站怎么让百度收录百度推广业务员电话
  • wordpress如何把菜单北京官网seo收费
  • WordPress滚轴动画主题搜狗搜索引擎优化论文
  • 帝国做网站的步骤seo是什么职位缩写
  • 怎样做网络推广产品seo运营学校
  • 网站开发有哪些方向seo的作用是什么
  • 怎样做自己的公司网站cps游戏推广平台
  • 广州网站建设海珠信科网站推广优化外包公司哪家好
  • 郴州红网兰州模板网站seo价格