为什么要使用泛型

首先我们先来看一段演示代码,如下所示,

1 public static void main(String[] args) {
2         List list = new ArrayList();
3         list.add("abc");
4         list.add(123);
5         list.add(HashMap.class);
6
7         System.out.println(list.get(0));
8 }

第2行,List里面的内容类型是Object类型,因此第3、4、5行可以接受String、Integer或者Class类型。然鹅,会存在两个严重的问题:

①在List集合中,增加元素时,集合不会记住元素的具体类型,对象的编译类型为Object类型,但是运行时类型仍然是本身的类型,如String等。

②在List集合中,取出元素时,需要对Object类型,进行转换,因为没有存储元素的真实类型,所以很容易出现ClassCastException异常。

因此我们的需求需要满足,第一编译能够识别元素的类型,第二不能出现类型强转出现的异常。于是泛型就出现了。于是出现了开发者很熟悉的一段代码:

在编译期间确定类型,只要不满足这个类型,则编译不通过。总结一下使用泛型带来的好处

1.类型确定,使得如果出现类型不一致在编译期间不同通过,而不是在运行期间抛出异常。

2.编码在逻辑代码中出现过多的强转,代码优雅性较好。

我们再来看一段如下代码,

 1 public static void main(String[] args) {
 2         List<String> a = new ArrayList();
 3         List<Integer> b = new ArrayList<>();
 4
 5         Class<? extends List> aClass = a.getClass();
 6         Class<? extends List> bClass = b.getClass();
 7
 8         System.out.println(aClass +" &&  "+ bClass);
 9         System.out.println(aClass == bClass);
10 }

打印出来的结果是   class java.util.ArrayList   &&  class java.util.ArrayList    true。因此,泛型的类型不会对集合实例时什么类型造成影响。如上图所示的泛型类型分别为String和Integer,但是getClass类型确是相同,都为ArrayList。因此想要定义两个重载函数,如果使用形参列表来区分重载,仅仅通过泛型不同时不可行的,演示代码如下所示,编译期间不通过。

泛型接口,泛型类,泛型方法

泛型,指的是“参数化”类型,什么是参数化类型呢?有点类似方法中的形参和实参,形参是方法中形式参数之意,比较抽象的概念,而实参是实际参数之意,拥有具体的数值,比较具体的概念。而参数化类型,表明在定义时形式化,在使用时具体化。下面看一下List接口的定义。

public interface List<E> extends Collection<E>

E就是参数化的类型,也就是泛型。这个接口叫作泛型接口,我们再看一下ArrayList的类定义;

public class ArrayList<E> extends AbstractList<E>implements List<E>, RandomAccess, Cloneable, java.io.Serializable

同样的这个类叫作泛型类,再来看泛型类中的泛型方法。如下所示,

 1 public boolean add(E e) {
 2         ensureCapacityInternal(size + 1);  // Increments modCount!!
 3         elementData[size++] = e;
 4         return true;
 5 }
 6
 7 public E remove(int index) {
 8         rangeCheck(index);
 9
10         modCount++;
11         E oldValue = elementData(index);
12
13         int numMoved = size - index - 1;
14         if (numMoved > 0)
15             System.arraycopy(elementData, index+1, elementData, index,
16                              numMoved);
17         elementData[--size] = null; // clear to let GC do its work
18
19         return oldValue;
20     }
21
22
23 public E get(int index) {
24         rangeCheck(index);
25
26         return elementData(index);
27 }

以上代码是ArrayList泛型类中的 add,remove,get。add方法的元素类型是E,remove方法的返回值类型也是E,get方法的返回值类型也是E。这个E就是最先我们接口中的定义的泛型接口参数E。   这就解释了为什么 在List<Integer> 中add("abc")会编译不通过,也解释了为什么在List<Integer>中 get(0)的返回值会是 Integer。

类型通配符

Object类是List的超类,然而List<Object >不是List<String>的父类,Number是Integer的抽象父类。然后List<Number>不是List<Integer>的父类。

因此,List<Integer>不能向上转型。此时就需要引入一个叫类型通配符的东西。类型通配符使用  ?  类表示。通配符“?”表示所有泛型的父类型。如下所示,

1 public List<?> filter(List<?> list) {
2
3
4
5         return list;
6 }

List<String> aa = new ArrayList();List<String> filter = (List<String>)filter(aa);在客户端可以直接调用filter方法,返回值依然是List类型,泛型为?即所有泛型的父类型,因此使用List<String>强转即可。使用类型通配符只能查询过滤或者统计元素,不能进行新增等操作,因为类型是抽象的,新增需要明确的类型。这里要提一下,我们

这里需要指出,我们在应用时经常要对  ?做出约束, 比如现在上述的  filter方法中,的形参,只能传递  Integer的父类。那代码就变成了:

public static List<?> filter(List<? super Integer> list) {return list;
}

ps:Integer和Integer的父类Number都是可的,List<Integer>、List<Number> 等。客户端调用如下所示。

List<Number> aa = new ArrayList();

List<Number> filter = (List<Number>)filter(aa);

和<? super Integer>相对的是<? extends Number>表示形参中的类型只能是Number类型或者是他的子类。

1 public static List<?> filter(List<? extends Number> list) {
2
3         return list;
4 }

最后强调一下

1.在新增一个泛型类时候,在类后面待上泛型,这个泛型不能是通配符“?”,而且如果要表示继承关系只能使用<T extends  父类>的形式,不能使用<T super 某个类>。

2.静态资源不识别泛型。静态变量,静态方法,静态方法块,静态类不识别泛型。

转载于:https://www.cnblogs.com/sunshine798798/p/9749964.html

Java基础之泛型的使用相关推荐

  1. Java基础之泛型简单讲解(通俗易懂)

    Java基础之泛型简单讲解(通俗易懂) 1. 前言 2. 简单例子对比理解 2.1 未使用泛型例子--ArrayList 2.2 使用泛型的例子 2.2.1 ArrayList 举例 2.2.2 Ha ...

  2. java基础之泛型(Generics)

    泛型,广泛存在于各种开源框架及容器集合类中,在我们阅读源码的过程中一定会碰到,作为java基础知识的一个重要模块,对泛型的理解和掌握有助于我们在之后的源码阅读中借鉴框架思想以及在项目开发中灵活应用泛型 ...

  3. 14. Java基础之泛型

    一. 泛型概念的提出(为什么需要泛型)? 首先,我们看下下面这段简短的代码: 1 public class GenericTest { 2 3 public static void main(Stri ...

  4. 【JAVA基础】java基础之-泛型详解

    写在前面的话 脑子是个好东西,可惜的是一直没有搞懂脑子的内存删除机制是什么,所以啊,入行多年,零零散散的文章看了无数,却总是学习了很多也忘了很多. 痛定思痛的我决定从今天开始系统的梳理下知识架构,记录 ...

  5. Java基础之泛型反射

    a.泛型 含义:是JDK1.5的新特性,本质是参数化类型,即所操作的数据类型被指定为一个参数,使用时通过传参来指定具体的类型. 好处:安全简单.具体体现在提供编译时的强类型检查,而不用等到运行:可避免 ...

  6. Java基础 Day14 泛型

    //为什么要使用泛型 //1.解决元素存储的安全性的问题 //2.解决获取元素时,须要类型转换的问题 //未使用泛型 package org.tizen.test;import java.util.A ...

  7. Java基础:泛型的使用

    泛型的使用 定义和使用含有泛型的类 定义和使用含有泛型的接口 泛型通配符<?>的使用 定义和使用含有泛型的类 public class FanXing<T> {public v ...

  8. Java基础学习——泛型(generics)学习一

    概述 在JDK 5.0,Java语言引入了好几个新的功能,其中很重要的一个就是泛型(generics). 本文就是对泛型的一个概述.你可以很熟悉其他语言中的类似结构,比如C++里的模板(templat ...

  9. Java基础——Day18——泛型,collections,set,map

    Day 18 一.泛型(掌握) 参数化数据类型 创建类的时候无法确定属性的数据类型,创建对象的时候根据实际需求确定数据类型 package com.qf.test;import java.util.A ...

最新文章

  1. Python fileinput模块:逐行读取多个文件
  2. 随机森林RF中的两个随机 抽样随机 特征选取随机 文章解释的好的
  3. vue判断a是否可点击_判断 a 和 b 里面元素是否一致:一致输出True,否则输出False...
  4. Ruby on Rails 實戰聖經阅读(三)
  5. 【洛谷 P2051】 [AHOI2009]中国象棋(DP)
  6. 张凯江:架构能力-“构建”世界的能力
  7. MNIST竞赛准确度99+%技术详解,文末有福利~
  8. xhr返回值_XMLHttpRequest发送POST、GET请求以及接收返回值
  9. MVC系列——MVC源码学习:打造自己的MVC框架(一:核心原理)
  10. 如何高效设计游戏——从抽奖模型到圆桌算法
  11. 【数字信号处理】基于matlab GUI正选信号时域+频域分析【含Matlab源码 887期】
  12. 已知空间中ABC3点坐标与到D点的距离,求D点坐标
  13. 基于python的火车票订票系统的设计与实现_火车票售票系统的设计与实现
  14. 编译原理(陈火旺)-中国大学慕课05 语法分析——自下而上分析5 第2次单元测试
  15. C语言输出图形:宝塔形(三角形)字母。第一行A,第二行BB,第三行CCC……
  16. u盘插入计算机显示被写保护,u盘被写保护了怎么去掉保护,教您解除u盘被写保护...
  17. 破解第三课 关键跳和关键CALL
  18. 基于51单片机的波形发生器(四种波形)(毕业设计资料)
  19. 微信运动刷步数软件有哪些?微信运动刷步软件推荐[
  20. python抓取微信_python抓取搜狗微信公众号文章

热门文章

  1. C++实现LRU算法(LeetCode 146 LRU缓存机制)
  2. ndk中杀线程的办法
  3. mysql保存表出错1075_navicat出现错误1075怎么办
  4. java低层源码_Java线程池及其底层源码实现分析
  5. c mysql dll_PHP5.3以上版本没有libmysql.dll,以及由此带来的困扰
  6. vue中v-model和v-bind区别
  7. MultipartFile转为File
  8. php用win还是linux系统,做网站选择linux系统还是选择windows系统好?
  9. “n个球放入m个盒子是否为空”的方案数
  10. 单摆运动属于什么现象_物理模型中的隐含条件是什么