Java泛型

Java 1.5版本中增加了泛型。

为什么需要引入泛型?
在引入泛型之前,读取集合中的每一个元素都需要进行转换,如果在集合中插入了错误类型的对象,那么就会在程序运行时报类型转换的错误。在引入泛型后我们可以告诉编译器需要向集合中插入的元素类型,编译器会在插入元素时进行自动转换,并在编译时报告往集合中插入错误类型的代码。

在Java代码中还可以继续使用原生态类型例如List等的原因是因为向后兼容,让以前未使用泛型的代码保存合法,并且能够与使用泛型的代码进行交互。在新代码中不推荐使用List等原生态类型。
List 和 List<Object> 区别?
两种集合都允许插入任何类型的对象。简单说List逃避了编译器的类型检查,而List<Object>则明确告知编译器其可以保存任何类型的对象。

泛型有子类型化的规则,List<String> 是原生态类型List的子类型而不是List<Object>的子类型,所有可以将List<String> 类型的对象传递给List类型的参数但不能传递给List<Object>类型的参数:
package template;

import java.util.ArrayList;
import java.util.List;

/**
* @author: zhouzhaoping
* @description:
* @date: 2019-08-25
*/
public class Test1 {

  public static void main(String[] args) {
      List<String> list = new ArrayList<String>();
      list.add("1");
      list.add("2");
      list.add("3");
      list.add("4");
      list.add("5");
      test1(list);
      test2(list); // 报错
  }

  public static void test1(List list) {
      for (Object o : list) {
          System.out.println("test1:" + o.toString());
      }
  }

  public static void test2(List<Object> list) {
      for (Object o : list) {
          System.out.println("test2:" + o.toString());
      }
  }

}

使用原生态类型List会失去类型安全性,使用List<Object>这样的参数化类型则不会,为了更好的说明请参考下面的代码。

public static void main(String[] args) {
      List<String> strings = new ArrayList<String>();
      unsafeAdd(strings, new Integer(42));
      String s = strings.get(0);

  }

  private static void unsafeAdd(List list, Object o) {
      list.add(o);
  }

在最新的Java8中,上述的代码已经无法通过编译。
将List替换为List<Object>能看到更明确的报错信息。

在不确定集合元素类型的情况下使用无限制的通配符类型代替使用原生态类型

如果你需要筛选集合的交集,使用原生态类型你可以这样写:

public static int numElementsInCommon(Set s1, Set s2) {
      int result = 0;
      for (Object o1: s1) {
          if (s2.contains(o1)) {
              result++;
          }
      }
      return result;
  }

由于使用了原生类型,这样写是很危险的。
如果要定义一个参数化的类型(例如List<String>,因为不能使用List<E>定义),但不确定或不关心实际的参数类型则可以使用一个?来代替。

public static int numElementsInCommon(Set<?> s1, Set<?> s2) {
        int result = 0;
        for (Object o1: s1) {
            if (s2.contains(o1)) {
                result++;
            }
        }
        return result;
    }

可以将任何元素放入原生态类型的集合中,因此很容易破坏该集合的类型约束条件,例如如下代码可通过编译:

public static int numElementsInCommon(Set s1, Set s2) {
        int result = 0;
        for (Object o1: s1) {
            if (s2.contains(o1)) {
                result++;
            }
        }
        s1.add("1");
        s2.add(2);
        return result;
    }

但如下代码却不行:

public static int numElementsInCommon(Set<?> s1, Set<?> s2) {
        int result = 0;
        for (Object o1: s1) {
            if (s2.contains(o1)) {
                result++;
            }
        }
        s1.add("1");
        s2.add(2);
        return result;
    }

通过以上例子不难看出?通配符主要使用在函数的形参上且在该函数内部不会修改该集合的场景中。

数组与泛型

数组与泛型相比有两个重要的不同点,第一个是数组是协变的而泛型不是,例如如果Sub是Super的子类型,那么Sub[]也是Super[]的子类型。相反泛型则是不可变的:对于任意两个不同的类型Type1和Type2,List<Type1>和List<Type2>没有关系( 其实这是数组设计的缺陷而不是泛型)。
这个不同导致使用泛型可以比使用数组更容易发现错误,参考如下的代码:

public static void main(String[] args) {
        Object[] objectArray = new Long[1];
        objectArray[0] = "I don't fit in.";

    }

这段代码可以通过编译但在执行时会抛出异常。

public static void main(String[] args) {
        List<Object> o1 = new ArrayList<Long>();
        o1.add("I don't fit in.");
    }

而这段代码则无法通过编译,对比数组我们可以更早的发现错误。

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

推荐阅读更多精彩内容

  • Java1.5版本中增加了泛型。在没有泛型之前,从集合中读取到的每一个对象都必须进行转换。如果不小心插入了错误类型...
    塞外的风阅读 763评论 0 0
  • 前言 Java 5 添加了泛型,提供了编译时类型安全检测机制,该机制允许程序员在编译时检测到非法的类型。泛型的本质...
    czwbig阅读 453评论 0 0
  • 阅读目录 一、为什么会出现泛型 二、泛型会带来什么样的问题 1. 不能用基本类型实例化类型参数 2. 不能用于运行...
    架构师Javaspring阅读 3,447评论 0 0
  • 参数类型的好处 在 Java 引入泛型之前,泛型程序设计是用继承实现的。ArrayList 类只维护一个 Obje...
    杰哥长得帅阅读 861评论 0 3
  • 当你决定做一件事的时候,你必须在72小时之内完成它,否则你很可能永远不会做了。总而言之,就是要立即去做,不要有太多...
    旖旎风光护你行阅读 161评论 0 0