Java泛型

泛型的定义与作用

泛型即参数化类型,而参数概念,最熟悉的就是定义方法时有形参,然后调用此方法时传递实参。而参数化类型就是将类型由原来的具体的类型参数化,类似于方法中的变量参数,此时类型也定义成参数形式,然后在调用时传入具体的类型(类型实参)
泛型的本质是为了参数化类型

泛型的优点

1.编译时的强类型检查
泛型要求在声明时指定数据类型,Java编译器在编译时会对泛型代码做强类型检查,并在代码违反类型安全时发出告警。
2.避免了类型转换
未使用泛型:

List list = new ArrayList();
list.add("hello");
String s = (String) list.get(0);

使用泛型:

List<String> list = new ArrayList<String>();
list.add("hello");
String s = list.get(0);  

泛型编程可以实现通用算法
通过使用泛型,程序员可以实现通用算法,这些算法可以处理不同类型的集合,可以自定义,并且类型安全且易于阅读

PCES法则:泛型上下边界

泛型擦除原理,泛型桥方法

泛型擦除做了如下工作:
1.把泛型中的所有类型参数替换为Object,如果指定类型边界,则使用类型边界来替换。因此,生成的字节码仅包含普通的类,接口和方法。

2.擦除出现的类型声明,即去掉<>的内容,比如T get()方法,声明就变成了Object get();List<String>就变成了List。如有必要,插入类型转换以保持类型安全。

3.生成桥接方法以保留扩展泛型类型中的多态性。类型擦除确保不为参数化类型创建新类;因此,反省不会产生运行时开销

而对于泛型中的桥方法,举例如下

public class B extends A<String> {
    @Override
    public void setValue(String value) {
        System.out.println("---B.setValue()---");
    }
}

通过上述的泛型的擦除机制,实际A类中的方法应该是这样的

// A 类中的 setValue 方法
public void setValue(Object value){
    this.value = value;
}

这个时候就出现了B类中的setValue方法参数与A类中的setValue方法参数不一样。安装Java重写方法的规则,B类中单setValue方法实际上并没有重写父类中的方法,而是重载。
所以实际上B有两个setValue方法,一个自己的,一个继承来的。
所以在某些场景,比如反射调用B类中的方法的时候,就有可能会调到父类的setValue方法,但是Java编译器处理了这种情况 如下:

public final class com/example/myapplication/test/A extends com/example/myapplication/test/B {


  // access flags 0x1
  public setValue(Ljava/lang/String;)V
    // annotable parameter count: 1 (visible)
    // annotable parameter count: 1 (invisible)
    @Lorg/jetbrains/annotations/NotNull;() // invisible, parameter 0
   L0
    ALOAD 1
    LDC "t"
    INVOKESTATIC kotlin/jvm/internal/Intrinsics.checkNotNullParameter (Ljava/lang/Object;Ljava/lang/String;)V
   L1
    LINENUMBER 5 L1
    LDC "Not yet implemented"
    ASTORE 2
   L2
    ICONST_0
    ISTORE 3
   L3
    NEW kotlin/NotImplementedError
    DUP
    NEW java/lang/StringBuilder
    DUP
    INVOKESPECIAL java/lang/StringBuilder.<init> ()V
    LDC "An operation is not implemented: "
    INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
    ALOAD 2
    INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
    INVOKEVIRTUAL java/lang/StringBuilder.toString ()Ljava/lang/String;
    INVOKESPECIAL kotlin/NotImplementedError.<init> (Ljava/lang/String;)V
    CHECKCAST java/lang/Throwable
    ATHROW
   L4
    LOCALVARIABLE this Lcom/example/myapplication/test/A; L0 L4 0
    LOCALVARIABLE t Ljava/lang/String; L0 L4 1
    MAXSTACK = 4
    MAXLOCALS = 4

  // access flags 0x1041
  public synthetic bridge setValue(Ljava/lang/Object;)V
   L0
    LINENUMBER 3 L0
    ALOAD 0
    ALOAD 1
    CHECKCAST java/lang/String
    INVOKEVIRTUAL com/example/myapplication/test/A.setValue (Ljava/lang/String;)V
    RETURN
    MAXSTACK = 2
    MAXLOCALS = 2

  // access flags 0x1
  public <init>()V
   L0
    LINENUMBER 3 L0
    ALOAD 0
   L1
    LINENUMBER 3 L1
    INVOKESPECIAL com/example/myapplication/test/B.<init> ()V
    RETURN
   L2
    LOCALVARIABLE this Lcom/example/myapplication/test/A; L0 L2 0
    MAXSTACK = 1
    MAXLOCALS = 1

  @Lkotlin/Metadata;(mv={1, 4, 3}, bv={1, 0, 3}, k=1, d1={"\u0000\u0018\n\u0002\u0018\u0002\n\u0002\u0018\u0002\n\u0002\u0010\u000e\n\u0002\u0008\u0002\n\u0002\u0010\u0002\n\u0002\u0008\u0002\u0018\u00002\u0008\u0012\u0004\u0012\u00020\u00020\u0001B\u0005\u00a2\u0006\u0002\u0010\u0003J\u0010\u0010\u0004\u001a\u00020\u00052\u0006\u0010\u0006\u001a\u00020\u0002H\u0016\u00a8\u0006\u0007"}, d2={"Lcom/example/myapplication/test/A;", "Lcom/example/myapplication/test/B;", "", "()V", "setValue", "", "t", "app_debug"})
  // compiled from: A.kt
}

会发现其中存在两个setValue,其参数值不一样,其中Object类型的就是Java编译器帮我们生成的桥方法

类型边界

类型边界可以对泛型的类型参数设置限制条件
类型边界的语法形式如下:

<T extends XXX>

示例:

public class GenericsExtendsDemo01 {
    static <T extends Comparable<T>> T max(T x, T y, T z) {
        T max = x; // 假设x是初始最大值
        if (y.compareTo(max) > 0) {
            max = y; //y 更大
        }
        if (z.compareTo(max) > 0) {
            max = z; // 现在 z 更大
        }
        return max; // 返回最大对象
    }

    public static void main(String[] args) {
        System.out.println(max(3, 4, 5));
        System.out.println(max(6.6, 8.8, 7.7));
        System.out.println(max("pear", "apple", "orange"));
    }
}
// Output:
// 5
// 8.8
// pear

类型边界可以设置多个,语法形式如下:

<T extends B1&B2&B3>

类型通配符

类型通配符一般是使用?代替具体的类型参数。例如List<?>在逻辑上是List<String>等所有List<具体类型实参>的父类

上界通配符语法形式为<? extends Number>
下界通配符语法形式为<? super Number>
上界和下界通配符不能同时使用

无界通配符语法形式为<?>
其有两种应用场景:
1.可以使用Object类中提供的功能来实现的方法
2.使用不依赖于类型参数的泛型类中的方法

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

推荐阅读更多精彩内容