关于泛型你要知道二三事[1]

关于泛型你要知道二三事

本内容均为原创,如需转载请注明出处:https://www.jianshu.com/p/d13ed2b58c8a

写这篇文章的初衷,是对于大家遇到的几道泛型(Generic)题目的不理解。那不妨我们在这里
展开,好好讨论一下泛型这个鬼东西。

备注<由于内容很多,所以会通过几个章节依次讨论>

为了更好的说明泛型这个内容我会从以下几个方向依次展开讨论:

1、什么是泛型?
    i、什么是类型安全的
    ii、泛型的语法格式
2、为什么需要泛型?
3、泛型主要分类:
    i、泛型类
    ii、泛型方法
    iii、泛型接口
    iv、泛型构造器
4、泛型的注意事项:
    i、优点:确保数据安全性
        a、泛型中能使用基本数据类型
        b、不同类型的泛型对象能互相转换
    ii、反射对于泛型的影响
    iii、泛型边界问题
    iv、泛型的擦除:
5、jdk8增强的泛型类型推断
6、拓展jdk10增强的局部变量的类型推断

什么是泛型?

什么是泛型呢?就是一个广泛的类型,注意它首先是一个类型,其次因为广泛,所以就是不明确类型。
所以我们说泛型就是一个不明确的类型。那如果类型不明确我们如何使用呢?别着急我们往下继学。
泛型是从jdk1.5之后引入的新特性。它不光增加了java的新的语法,同样也改变了核心API中的许多类以及方法。常见的比如java.util.*。通过泛型,我们可以创建类型安全的类、接口等。

什么是类型安全的呢?

基于这个问题,我会在第二块中详细阐述这个问题。这里先不深入

泛型的语法格式

我们在后续的泛型分类中会详细介绍泛型不同的创建方式和细节,这里我们要注意泛型的书写方式!

通过一组<> 去定义泛型。然后在<>中编写任意的字母即可。但是不能以数字开头。
我们通常会通过在<>中定义26个英文字母的大写表示。一般常见的字母为T,E,K,V等。

例子:

<T> //定义一个泛型类型 T
<K,V> //定义了一个泛型 包含两个泛型类型分别是K和V

2 为什么需要泛型?

我们试想,如果没有泛型,假设在一下代码中,会出现什么问题?

测试代码1:

        List ls = new ArrayList();
        ls.add("str");
        ls.add(new Integer(12));
        for(int i = 0;i<ls.size();i++){
            Integer s = (Integer) ls.get(i);
            System.out.println(s);
        }

以上代码会出现问题,ClassCastException<类型转换异常>。原因大家应该都很清楚,那我们试想,如果没有泛型,所有对于数据的操作都会按照显式的方式进行转换,所以我们说泛型在一定程度上帮助我们做到了确保数据安全性。当然安全性我们还会通过其他示例来深入阐述。

测试代码2:

    public static void main(String[] args) {
        List lists = new ArrayList();
        lists.add("hello");
        lists.add(12);
        List<String> ls = new ArrayList<String>();
        ls.add("hello");
        ls.add(12);//the compile-time error
        
    }

以上代码我们能够很直观的看出来,如果对于一个没有声明泛型的泛型的List集合来讲,可以往集合中添加任意类型(注意只能是引用类型)。而对于声明类泛型类型为String的List集合而言只能添加Stirng对象,当要往List集合添加12时(注意,这里的12会做自动装箱),编译时会报错。很好帮我解决了数据验证的问题。其实我们很难有场景要在一个集合中填充不同对象,对于后期来讲这样是不太方便的。大多数场景下我们还是填充的统一类型数据。(当然有时候我们确实有添加不同对象的需求,我们在后续的例子中会展开讨论)。

测试代码3:此时泛型的行为时期

在这里我们将上述的代码编译之后,通过反编译工具打开再次查看:

public static void main(String[] args)
  {
    List lists = new ArrayList();
    lists.add("hello");
    lists.add(Integer.valueOf(12));
    List ls = new ArrayList();
    ls.add("hello");
  }

这里无论是lists集合还是ls集合,在编译完之后的我们发现,泛型都不存在了,而且12的填充确实调用了Integer.valueOf()进行了自动装箱。所以我们说泛型是一个编译器行为。那其实这也就为我们通过反射在运行期动态往一个泛型集合中添加不同数据类型埋下伏笔。

3、泛型分类

接下来我会通过四个方向依次详细说明泛型在不同情境下定义要遵守的一些规则。

泛型类:

public class Test01 {
    public static void main(String[] args) {
        //create generic type Gen instance and assign
        //generic type of Gen is Integer
        //it`s use of autoboxing to encapsulate 
        //the value 12 within an Integer Object
        Gen<Integer> g1 = new Gen<Integer>();
        g1.t = 12;
        g1.getT();
        //jdk1.7  enhancement type inference 
        Gen<String> g2 = new Gen<>();
        g2.t = "hello";
        g2.getT();
        //create generic type Gen instance and 
        //don`t assign generic type
        Gen g3 = new Gen();
        g3.t = new Date();
        g3.getT();
    }
}
//declared a generic type Gen
class Gen<T>{
    T t;
    public void getT(){
        System.out.println(t.getClass().getName());
    }
}

在这里说明了一个Generic类->Gen,泛型类型是T,我们上文提到过,泛型就是一个类型,那么这里的T你不防理解为一个类型。并且为了获取T类型方便一些,我们将T类型也声明为了一个成员变量。我们在代码中通过getT()方法获取成员变量T的Class对象的名称。其次我们在测试类创建了3个Gen的对象。
在第一个用例中:创建对象时指定类型为Integer,且通过给对象中的T类型赋值为12。我们发现获取到的Class对象的名称为Integer。
第二个用例中:创建对象时指定类型为String,且这里我们在对象创建中只通过<>,而没有在括号中给具体的类型,这是jdk1.7中的增强类型推断,因为已经声明过时String类型,所以会自动推断出Gen对象的T类型是String。同样这里获取到的Class对象名称为String。
第三个用例中:创建对象时没有指定泛型类型,我们这里直接赋值发型可以给T传入任何Object类型。其实这就是典型的擦除。我们后续分享会逐一解开这个面纱。这里获取到的泛型的name成为了Object。

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

推荐阅读更多精彩内容

  • 自定义泛型 1.1、泛型的定义介绍 在集合中,不管是接口还是类,它们在定义的时候类或接口名的后面都使用<标识符>,...
    Villain丶Cc阅读 8,700评论 0 7
  • Scala与Java的关系 Scala与Java的关系是非常紧密的!! 因为Scala是基于Java虚拟机,也就是...
    灯火gg阅读 3,407评论 1 24
  • 一、学习内容 Grace 分享了她的金钱观: 1. 敢于定价 时间是很宝贵的,我是值得被付费。 要敢为自己提供的...
    Joyceloveslife阅读 190评论 0 0
  • 01 今天继续读了哀曲无闻的因书,读到了第二节《懂得自律,才有可能放纵人生》。从题目上或许你可以看出这一节的主题就...
    明诚看世界阅读 516评论 0 2