前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java泛型01 : 泛型简介、泛型由来、入门示例和其他说明

Java泛型01 : 泛型简介、泛型由来、入门示例和其他说明

作者头像
用户7886150
修改2020-12-15 10:38:18
5280
修改2020-12-15 10:38:18
举报
文章被收录于专栏:bit哲学院

参考链接: Java中的异常类型与示例

超级通道: Java泛型学习系列-绪论 

本章主要对Java泛型进行整体性介绍。 

1.泛型简介 

百度百科(修改版): 

 泛型是Java SE 1.5的新特性,泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。这种参数类型可以用在类、接口和方法的创建中,分别称为泛型类、泛型接口、泛型方法。  在Java SE 1.5之前,没有泛型的情况的下,通过对类型Object的引用来实现参数的“任意化”,“任意化”带来的缺点是要做 显式的强制类型转换,而这种转换是要求开发者对实际参数类型可以预知的情况下进行的。对于强制类型转换错误的情况 ,编译器可能不提示错误,在运行的时候才出现异常,这是一个安全隐患。  泛型的好处:使用泛型,首先可以通过IDE进行代码类型初步检查,然后在编译阶段进行编译类型检查,以保证类型转换的安全性;并且所有的强制转换都是自动和隐式的,可以提高代码的重用率。 

2.泛型由来 

泛型的思想早就存在,在C++中的类模板(Template)就是用到了泛型的思想。  在JDK1.5之前,可以通过继承实现这种泛型思想。  查看ArrayList(JDK1.5)之前的定义如下: 

public class ArrayList extends AbstractList implements List, RandomAccess, Cloneable, Serializable

{

  private static final long serialVersionUID = 8683452581122892189L;

  private transient Object[] elementData;

  private int size;

  //...

  public boolean add(Object paramObject)

  {

    ensureCapacity(this.size + 1);

    this.elementData[(this.size++)] = paramObject;

    return true;

  }

  //...

  public Object get(int paramInt)

  {

    RangeCheck(paramInt);

    return this.elementData[paramInt];

  }

可以看到,ArrayList的本质是一个Object数组Object[] elementData。  这种做法虽然实现了泛型思想,但是有以下问题: 

ArrayList实例化之后,可以随意添加任意类型的对象(Obeject是任意引用类型的基类)。获取元素的前提是:需要提前知道列表元素的类型。获取列表元素时,都需要进行显式类型转换。容易发生类型转换出错的问题。 

如下面的代码: 

//JDK1.5之前的ArrayList的用法

ArrayList arrayList = new ArrayList();

//可以随意添加任意类型的对象

arrayList.add(1);//Integer

arrayList.add("1");//String

//张三前辈知道第一个元素是Integer类型的,所以他写的程序没错

Integer integer = (Integer) arrayList.get(0);

LOGGER.info("张三前辈取值:" + integer);

//李四不知道第二个元素是什么类型,因为张三前辈已经离职了,但他看张三前辈使用Integer取值的,

// 所以他猜测也是Integer类型的,但是他没想到实际是String类型的,所以会报类型转换错误

Integer integer1 = (Integer)arrayList.get(1);

LOGGER.info("李四后生取值:" + integer1); 

代码执行结果: 

INFO - 张三前辈取值:1

2018-02-12 16:56:57 INFO  BeforJDK5:26 - 张三前辈取值:1

Exception in thread "main" java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer

    at pers.hanchao.generics.before.BeforJDK5.main(BeforJDK5.java:29) 

为了解决上面的问题,JDK1.5加入了泛型。加入泛型是为了解决类型转换的安全隐患,具体体现如下: 

解决泛型对象实例化之后,可以随意添加任何类型的对象的问题。解决获取泛型元素前,需要提前确定元素的类型的问题。解决获取元素时,需要进行显式类型转换的问题。解决容易出现类型转换出错的问题。 

使用泛型的解决方式: 

//JKD1.5之后的ArrayList

ArrayList<Integer> integerArrayList = new ArrayList<Integer>();

integerArrayList.add(1);//添加Integer正常

//不能添加String类型,因为无法通过IDE的初步类型检查

//integerArrayList.add("1");

//王五不需要问前辈,就很容易知道这个列表存储的是Integer

Integer integer2 = integerArrayList.get(0);

LOGGER.info("王五后生取值:" + integer2); 

运行结果 

2018-02-12 16:56:37 INFO  BeforJDK5:39 - 王五后生取值:1 

3.入门示例 

泛型可以应用在类、接口和方法的创建中,分别称为泛型类、泛型接口和泛型方法。下面对这三种使用方式提供简单的入门示例: 

package pers.hanchao.generics.hello;

import org.apache.log4j.Logger;

/**

 * 泛型类示例

 * Created by 韩超 on 2018/2/12.

 */

public class HelloWorld<T> {

    private final static Logger LOGGER = Logger.getLogger(HelloWorld.class);

    private T t;

    public T getValue() {

        return t;

    }

    public void setValue(T t) {

        this.t = t;

    }

    public static void main(String[] args){

        LOGGER.info("泛型类示例:");

        //泛型类示例

        HelloWorld<String > helloWorld = new HelloWorld<String >();

        helloWorld.setValue("Hello World!");

        //IDE提供的类型检查确保只能设置String类型的对象,Long类型报错

        //helloWorld.setValue(5211314L);

        LOGGER.info(helloWorld.getValue());

        HelloWorld<Long> helloWorld1 = new HelloWorld<Long>();

        helloWorld1.setValue(5211314L);

        //IDE提供的类型检查确保只能设置Long类型的对象,String类型报错

        //helloWorld1.setValue("Hello World!");

        LOGGER.info(helloWorld1.getValue() + "\n");

        LOGGER.info("泛型方法示例:");

        //泛型方法示例

        printHelloWorld("Hello World!");

        printHelloWorld(5211314 + "\n");

        LOGGER.info("泛型接口示例");

        //泛型接口示例

        MyInterface myHelloWorld = new MyHelloWorld();

        //Number类型都可以

        myHelloWorld.print(5211314L);

        myHelloWorld.print(521);

        //String类型不可以

        //myHelloWorld.print("S");

    }

    /**

     * <p>Title: 泛型方法</p>

     * @author 韩超 2018/2/12 17:14

     */

    static <T> void printHelloWorld(T t){

        LOGGER.info(t);

    }

    /**

     * <p>Title: 泛型接口</p>

     * @author 韩超 2018/2/12 17:15

     */

    interface MyInterface<T extends Number>{

        void print(T t);

    }

    static class MyHelloWorld implements MyInterface{

        @Override

        public void print(Number number) {

            LOGGER.info(number);

        }

    }

}

运行结果: 

2018-02-12 17:22:15 INFO  HelloWorld:23 - 泛型类示例:

2018-02-12 17:22:15 INFO  HelloWorld:27 - Hello World!

2018-02-12 17:22:15 INFO  HelloWorld:31 - 5211314

2018-02-12 17:22:15 INFO  HelloWorld:33 - 泛型方法示例:

2018-02-12 17:22:15 INFO  HelloWorld:53 - Hello World!

2018-02-12 17:22:15 INFO  HelloWorld:53 - 5211314

2018-02-12 17:22:15 INFO  HelloWorld:38 - 泛型接口示例

2018-02-12 17:22:15 INFO  HelloWorld:67 - 5211314

2018-02-12 17:22:15 INFO  HelloWorld:67 - 521 

4.其他说明 

泛型是向前兼容的:JDK1.5之前未使用泛型类可以不加修改的继续工作,但是却无法享受泛型的好处的。泛型的设计初衷:是为了减少类型转换错误产生的安全隐患,而不是为了实现任意化,一定要记住这个初衷。

本文系转载,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文系转载前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档