Java从入门到放弃之 泛型

是真要放弃, 因位要学Kotlin, 学Java纯粹就是为了能看懂API和Java库.

泛型在我用过的语言中并不存在, 有必要认真做笔记.

  1. 什么是泛型
    泛型是java的一个语言特性, 使得类型可以作为参数.

  2. 为什么要泛型
    编译期的强类型检查
    不需要类型转换
    泛型算法--使得程序可以处理不同数据类型的集合

  3. 泛型是如何工作
    类型安全
    如果声明List<Integer>, 编译器在编译期间就会阻止你往list里添加非integer元素.
    类型擦除
    泛型只是一个语法糖, 通过泛型添加的类型信息, 会被编译器从字节码中删除.

用代码解释

不通用的类

class Foo {
  private int t;
  public void set (int t) {
    this.t = t;
  }
  public int get () {
    return this.t;
  }
}

这个类有一个属性t, 显然t的类型只能是int, 这个类无法处理其他的类型.
如果运行:

    Foo o = new Foo();
    o.set("abc");
    //Exception in thread "main" java.lang.Error: Unresolved compilation ...

收获编译器警告.

通用但不安全的类

把Foo的int替换成Object, 由于所有的类型都是Object的子类, Foo成了万金油类.

class Foo {
  private Object t;
  public void set (Object t) {
    this.t = t;
  }
  public Object get () {
    return this.t;
  }
}
...
Foo o = new Foo();
o.set("abc");
o.set(13);

Foo的实例可以接受任何类型的值, 这很方便, 但有安全隐患, 我们不得不手动添加各种类型判断, 因为我们不知道t的类型会是什么.

泛型

使用泛型改写我们的类

class Foo<T> {
  private T t;
  public void set (T t) {
    this.t = t;
  }
  public T get () {
    return this.t;
  }
}

这里我们使用了泛型语法<T> 添加了一个泛型类型T, T叫做 type parameters, 类型参数, 也叫类型变量.

类型变量可以是任何非原始数据类型, 如类, 接口, 数组, 或其他类型变量.
类型变量命名习惯:

E - Element (used extensively by the Java Collections Framework)
K - Key
N - Number
T - Type
V - Value
S,U,V etc. - 2nd, 3rd, 4th types

实例化泛型, 将T替换成具体的类型, 传入type argument类型参数.

    Foo<String> o = new Foo<String>();
    // 可以用简便的语法
    // Foo<String> o = new Foo<>();
    o.set("abc");
    o.set(13); // Error

    Foo<Integer> oo = new Foo<Integer>();
    oo.set(12);
    oo.set("s"); //Error

这里分别传入StringInteger类型. 这就是泛型的好处, 既有类型检查又有灵活性.

泛型方法

泛型方法引入了自己的类型参数, 静态和构造函数都可以是泛型方法.
泛型方法代码: https://docs.oracle.com/javase/tutorial/java/generics/methods.html

绑定的类型参数 ( bounded type parameters )

绑定的类型参数限制了参数的类型只能是某类型或者某类的子类.

    public <U extends Number> void inspect(U u){
        System.out.println("T: " + t.getClass().getName());
        System.out.println("U: " + u.getClass().getName());
    }

这里的extends 同时表示继承或实现(implements)

通配符

?号是一个通配符, 表示一种未知的类型, 但通配符不会用在方法调用, 实例创建时.

Upper Bounded Wildcards

只限制最高

List<? extends Number> // Number 和它子类
List<Number> // 只是Number类

Unbounded Wildcards

不限制类型
比如一个方法可以用Object类的功能实现, 或代码并不依赖类型参数时.

List<?> //接受任意类型 

Lower Bounded Wildcards

只限制最低

 List<? super Integer> // LBW, 接受Integer和任何Integer的父类
 List<Integer> // 只是Integer

类型继承关系

List<Integer> 并不是 List<Number>的子类。它们的关系是这样的:

generics-wildcardSubtyping.gif

原图: https://docs.oracle.com/javase/tutorial/java/generics/subtyping.html

通配符使用指南

使用通配符时, 先思考数据的流动方向, 如:

copy(src, dest);

src是数据的流入变量, dest流出变量.

  • 对于流入变量, 使用upper bounded wildcard, 用extends
  • 对于流出变量, 使用lower bounded wildcard, 用super
  • 如果流入变量可以被Object类的方法使用, 使用unbounded wildcard
  • 如果既是流入又是流出变量, 不用通配符.

方法的返回类型, 不使用通配符.

泛型数组

    Object[] foo = new String[2];
    foo[0] = "Hello";
    foo[1] = 2;      //错误

上面的代码会报错, 这是因为数组在运行时也有类型检查, 这说明数组会保留类型信息, 而编译器会移除泛型类型信息, 这种矛盾导致Java不允许给泛型数组赋值.

class GA<T> {
  public T[] foo; // 允许
  public T[] bar = new T[5]; // 错误
}

泛型使用限制

不能定义静态泛型属性, 因静态属性被所有对象共享, 属性的类型将无法确定.

public class <T>
{
   private static T property; //错误
}

不能做类型转换或执行instanceof
因泛型信息在编译时已被擦除, 所以无法做类型相关的操作.

泛型类无法继承Throwable类, 方法也不能创建或捕获参数化的类型.
类不能包含两个在类型擦除之后有相同签名的重载方法.
不能创建类型参数实例.
不能使用基础数据类型作为泛型参数类型.

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

推荐阅读更多精彩内容

  • Java 泛型是 Java 5 引入的一个重要特性,相信大多数 Java 开发者都对此不陌生,但是泛型背后的实现原...
    JohnnyShieh阅读 2,059评论 6 37
  • 对象的创建与销毁 Item 1: 使用static工厂方法,而不是构造函数创建对象:仅仅是创建对象的方法,并非Fa...
    孙小磊阅读 1,969评论 0 3
  • 一. 为什么需要泛型 先来说说一个简单的实例。 这个例子很简单,有一个仓库Store,里面储存了一个数据data,...
    wo883721阅读 768评论 0 3
  • 前言 人生苦多,快来 Kotlin ,快速学习Kotlin! 什么是Kotlin? Kotlin 是种静态类型编程...
    任半生嚣狂阅读 26,171评论 9 118
  • 我以为不会在乎这些。我以为我不会哭。 当我一次次站起来又跌倒后,当我所做的一切努力被全盘否定后,当那无意嘲讽却格外...
    Xiang_你说阅读 228评论 0 0