Java 基础 之 泛型

一:什么是泛型


    泛型在我们的代码中使用非常广泛的一部分知识,今天就系统的把泛型总结一下,并记录自己的学习历程。

    泛型,即“参数化类型”。顾名思义,就是将类型由原来的具体的类型也定义成参数形式。然后在使用/调用时传入具体的类型(实参)。这种参数类型可以用在类、接口和方法中,分别被称为泛型类、泛型接口、泛型方法。

二:泛型的引入


    首先,让我们先来设计一个加法计算的类,可以计算int, double。

    如果有一天我们需要再计算char,string的加法,那我们还得新增这样类很多个,显然不符合软件设计的规范,下面我就来更新一下我们的代码,把所有的参数都变成object.

好了,让我们来测试一下,我们的这个新类能不能完成,int, double,String 的加法计算

    通过试验发现,将参数抽象成object类型 后,发现只需要定义一个类就可以搞定感觉这样挺完美的了。但是每次都需要强制转换,这样的代码设计太麻烦了!下面让我们再升级一次我们的code,见证一下泛型的好处,不需要我们每次都强制类型转换。

三:泛型类


  泛型类型用于类的定义中,被称为泛型类。

  泛型类的定义格式:class类名称<泛型标识>,

  1:泛型标识可以随便写为任意标识,常见的如T、E、K、V等形式的参数常用于表示泛型,

  2:泛型的类型参数只能是类类型,不能是简单类型,

  3:在实例化泛型类时,必须指定T的具体类型

下面来定义一个泛型类,让他满足各种类型的加法操作

    通过上面的试验,是不是发现如果利用泛型来实现就只需要创建一个泛型类,然后实例化时传入参数类型,不需要进行强制类型转化就可以正确计算出结果!

    但是有人就会提出来,可不可以设计成一套标准啊,我们定义这样的一个泛型接口,让具体的操作人员来实现这个标准,答案是当然可以!

四:泛型接口


    泛型接口与泛型类的定义及使用基本相同

    泛型接口的定义格式:publicinterface Generator<T>

    定义一个泛型接口(定义参数的设定和获取)

    定义一个泛型类来实现这个泛型接口

    但是有些人说我们可能只需要做int或String或Double的计算,不需要其他的计算,那能不能做成定制化的那?当然也是可以的,看下面的定义:

    是不是发现泛型接口,更加的灵活,如果我们只需要做String的加法那就把T换成具体的数据类型String即可

总结:

      如果一个类实现了一个泛型接口,那么该类也必须是泛型的:

      GenericAdd<T> implements GenericInterface<T>

      如果一个类实现了一个特定类型的泛型接口,那么该类不是泛型的:

      GenericAdd implements GenericInterface<Integer>

五:泛型方法


      有泛型类,泛型接口,那一定也有泛型方法。泛型类,是在实例化类的时候指明泛型的具体类型;泛型方法,是在调用方法的时候指明泛型的具体类型 。泛型方法指返回值和参数都用泛型表示的方法。

    泛型方法的定义格式:void doTest<T t>

        1:普通类中的泛型方法

    通过上面的测试发现在普通类的中的定义一个泛型方法用T,V…来参数化,使用也很简单,只需要在调用时传入具体的参数类型。

    2:泛型类中的泛型方法

    在上面的泛型类中定义了三个泛型方法,在我们的测试中看到226行编译出错了,说明了第一个泛型方法只能传入和泛型类实例化时一样的类型,第2个和第3个泛型方法可以处理任意的类型。

    在泛型类(<T>)中定义泛型方法时如果不在返回值前面指定<T>泛型类型,那这个泛型方法就只能处理与泛型类实例化时声明的类型,如上面的第1个泛型方法 getClassInfo1

    在泛型类(<T>)中声明了一个使用泛型E的泛型方法,这种泛型E可以为任意类型。可以与泛型类实例化时声明的T相同,也可以不同。如上面的第2个泛型方法 getClassInfo2

在泛型类(<T>)中声明了一个泛型方法,使用泛型T,其实这个T是一种全新的类型,可以与泛型实例化时声明的T不是同一种类型。如上面的第3个泛型方法 getClassInfo3可以处理People类

    3:静态泛型方法

    在泛型类或泛型接口中,静态函数无法使用泛型,所以,若要static方法需要使用泛型能力,必须使其成为泛型方法(静态泛型方法)

静态泛型方法也很简单,就是在普通泛型方法前面加上一个static,使用方式也和普通的静态方法一样,直接类名.方法名就可以了!

  4:泛型方法的重载

    普通方法有重载,当然泛型方法也是有重载的,是因为java编译器在编译时会对泛型做擦除功能,所以T就会变成Object, <T extends Ape>转成Ape, <T extends People> People。当我们这样定义泛型方法:

                public  void doTest(T t)

                public void doTest(T t)

                public  void doTest(T t)

    编译后就变成了:

                publicvoid doTest(Object t)

                publicvoid doTest(People t)

                public void doTest(Ape t)

    编译后的三个方法就是我们很熟悉的doTest重载,下面就用code来见证一下:

使用也很简单和普通的泛型方法一样

    s, pe, a分别是三个类类型。

六:泛型通配符


    前面我们介绍了泛型的基本用法、类型擦除。在泛型的使用中,还有个重要的东西叫通配符,下面就介绍通配符的使用。

    我们先定义三个类:Ape, People继承自Ape,Student继承自People

    我们再定义一个泛型类

    完成了基础的class建设后,我们来讲通配符的使用

      1:<? extends T>

        <? extends T>表示上界通配符,它表示T以及T的子类, 类型最高是T。

在上面的的code中我们定义了 <? extends People>的泛型类,理论上,他可以指向和存放自己以及所有所有属于他的子类。但是第141,142,143却都报错了,编译器却告诉我们gp不能存放任何元素,这好像和我们前面的解释相反:这是因为编译器在编译时要做类型安全检查,当我们这样定义gp时,就是告诉编译器gp存的是People以及People的子类可能是Student,可能是People,也可能是其他的子类,编译器没办法保证gp的下限是什么,就不知道到底该指向什么类型。

总结: extends不能用于参数类型限定。

    2:<? super T>

    <? super T>表示下界通配符: 表示T以及T的超类

在上面的的code中我们定义了 <? super People>的泛型类,理论上,他可以指向和存放自己以及People父类。但是我们的测试结果却是:他可以添加People以及People的子类Student,不能添加他的父类。这好像和我们前面的解释相反:这是因为当我们这样定义gp1时,就是告诉编译器gp1存的是People以及People的父类可能会放People,可能会放Ape,这样编译器可以确定,gp1最低的标准就是People,这样编译器就把下限设置为people,所以我们可以存放Student,People。

总结:super可用于参数类型限定

7: 泛型实践


写这么多,当然有点乏味,下面就写个获取最大值和遍历数组的工具泛型来实践一下:

1:创建一个泛型接口,把类型参数限制成实现了Comparable接口的类

2:再编写一个泛型类继承我们的泛型接口,实现获取最大值接口,在定义一个泛型方法,完成数组的遍历

3:在main 函数中实例化泛型类并定义2个数组来测试获取最大值功能,2个类数组来测试遍历功能

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 200,612评论 5 471
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,345评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 147,625评论 0 332
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,022评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,974评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,227评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,688评论 3 392
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,358评论 0 255
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,490评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,402评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,446评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,126评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,721评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,802评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,013评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,504评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,080评论 2 341

推荐阅读更多精彩内容

  • 转载: https://blog.csdn.net/s10461/article/details/53941091...
    DaneYang阅读 485评论 1 6
  • 泛型的定义及使用 1. 定义泛型: 2. 类中使用泛型 3. 使用泛型类 4. 使用泛型的优势? 多泛型变量的定义...
    xue57233阅读 427评论 0 1
  • Java 泛型,你了解类型擦除吗? 1. 函数上的泛型定义 当函数中使用了一个不明确的数据类型,那么在函数上就可...
    沈默的头号狗腿阅读 356评论 0 0
  • 参考文章:https://blog.csdn.net/s10461/article/details/5394109...
    Owen270阅读 235评论 0 0
  • 孔子说,“朝闻道夕死可矣。”意思是早晨明白做人的道理,晚上死也可以了。用现在的话来说,就是“终身学习”。 今日上的...
    明心zyl阅读 601评论 0 1