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

超级通道: 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之前未使用泛型类可以不加修改的继续工作,但是却无法享受泛型的好处的。
  • 泛型的设计初衷:是为了减少类型转换错误产生的安全隐患,而不是为了实现任意化,一定要记住这个初衷。
  • 5
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值