前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >细说java系列之泛型

细说java系列之泛型

作者头像
编程随笔
发布2019-09-11 16:09:16
5770
发布2019-09-11 16:09:16
举报
文章被收录于专栏:后端开发随笔后端开发随笔

什么是范型

简言之,范型是Java支持在编译期进行类型检查的机制。 这里面包含2层含义:其一,可以使用范型进行类型检查;其二,在编译期进行类型检查。 那么,什么叫做在编译期进行类型检查?可以在运行时进行类型检查吗?带着这些疑问,我们一步步深入范型。

范型有什么用途

1. 使用Java集合类时明确指定元素类型

在使用Java提供的集合类时,必须指定具体的类型。举个例子:

代码语言:javascript
复制
// 创建只能存放String类型对象的列表,当存放其他类型的对象时将会编译报错
List<String> strList = new ArrayList<String>();
strList.add("test");
strList.add(1);

当添加非String类型的对象到strList时,编译将报错:

代码语言:javascript
复制
> javac -encoding UTF-8 GenericTest.java
GenericTest.java:27: 错误: 对于add(int), 找不到合适的方法
                strList.add(1);
                       ^
    方法 Collection.add(String)不适用
      (参数不匹配; int无法转换为String)
    方法 List.add(String)不适用
      (参数不匹配; int无法转换为String)
注: 某些消息已经过简化; 请使用 -Xdiags:verbose 重新编译以获得完整输出
1 个错误

也就是说,通过泛型可以在我们使用Java集合类时,在编译期就避免将不正确的类型添加到集合对象中,而且从语法上就可以很方便地看出集合对象中存放的对象类型,算是一个语法糖。

2. 定义泛型类

首先,我们来看看如果不使用泛型,我们如何解决问题。 假设我们需要定义一个Box类,用于存放对象,通常我们会定义为如下形式(大多数时候我们创建的对象类就是这样):

代码语言:javascript
复制
class Box {
    private String obj = null;

    public String getObj() {
        return obj;
    }

    public void setObj(String obj) {
        this.obj = obj;
    }
}

很显然,如果我们实例化一个Box对象,那么这个“盒子”里面只能存放字符串类型的对象。如果强行让它存放其他类型的对象,将会在编译时报错:

代码语言:javascript
复制
Box box = new Box();
//box.setObj("string");
box.setObj(1);
代码语言:javascript
复制
javac -encoding UTF-8 GenericTest.java
GenericTest.java:32: 错误: 不兼容的类型: int无法转换为String
                box.setObj(1);
                           ^
注: 某些消息已经过简化; 请使用 -Xdiags:verbose 重新编译以获得完整输出
1 个错误

我们辛辛苦苦(需要编码的哈^^^^)创建了一个“盒子”类,原本是希望可以存放各种各样的对象,结果却只能存放字符串!这是非常不经济的。 如果我们需要存放Integer类型的对象,则需要创建一个新“盒子”类。 当然了,最简单的改造就是让Box类直接存放的对象类型为Object,就可以在Java世界存放所有类型的对象了。

代码语言:javascript
复制
static class Box {
    private Object obj = null;

    public Object getObj() {
        return obj;
    }

    public void setObj(Object obj) {
        this.obj = obj;
    }
}

OK,这时候我们可以任意往“盒子”对象中放任何类型的对象了,既不会在编译时报错,也不会在运行时报错。

代码语言:javascript
复制
Box box = new Box();
//box.setObj("string");
box.setObj(1);

看起来我们已经很完美地解决了问题,但是!当我们从“盒子”里取出对象时,如何知道它是什么类型呢? 当然,我们也是有办法的,因为在Java中可以通过instanceof判断对象类型,而且还可以进行对对象进行强制类型转换。

代码语言:javascript
复制
Box box = new Box();
//box.setObj("string");
box.setObj(1);
Object obj = box.getObj();
if(obj instanceof String) {
    System.out.println("object type is String");
    String strObj = (String)obj;
    System.out.println(strObj);
}else if(obj instanceof Integer) {
    System.out.println("object type is Integer");
    Integer intObj = (Integer)obj;
    System.out.println(intObj);
}

但是,如果采用这样的方式编写代码,会不会太繁琐啦?而且代码的复用性很差。 OK,到这里我们可以看到,不使用泛型,或者Java不支持泛型,我们依然可以干活,但是干活的方式太笨啦!从某种角度讲可能是非常糟糕的方式。 那么,如果使用泛型,会带来什么样的便利呢? 如下所示,将Box声明为泛型类:

代码语言:javascript
复制
static class Box<T> {
    private T obj = null;

    public T getObj() {
        return obj;
    }

    public void setObj(T obj) {
        this.obj = obj;
    }
}
代码语言:javascript
复制
Box<String> strBox = new Box<String>();
strBox.setObj("string");
String strObj = strBox.getObj();
System.out.println(strObj);

Box<Integer> intBox = new Box<Integer>();
intBox.setObj(1);
Integer intObj = intBox.getObj();
System.out.println(intObj++);

如上所示,当我们把Box声明为泛型类之后,在需要存放指定类型的对象时,只需要在实例化Box对象时明确指定对象类型即可。 另外,当从Box中取出对象后也可以很明确地知道对象类型,不需要对对象进行强制类型转换,最重要的是这使得代码复用非常方便。

3. 定义泛型方法

泛型方法的定义比较特别,需要在方法的返回值类型之前添加泛型标志。

代码语言:javascript
复制
public static <T> void printObj(T obj) {
    System.out.println(obj);
}

需要特别注意:在泛型类中定义的方法不一定就是泛型方法!如上Box类中的set/get方法并不是泛型方法。 泛型方法的作用似乎没有泛型类那么大,但是在某些特定的场合使用泛型方法会带来一定的便利。

4. 定义泛型接口

代码语言:javascript
复制
interface Operator<T> {
    void printObj(Object obj);
}

使用泛型注意事项

范型仅仅是一种在Java代码进行编译时的静态类型检查机制,是编译时检查。无法在运行时进行类型检查,实际上在运行时已经把类型擦除了。 那为什么对象类型会被擦除?以及存在类型擦除将会带来什么影响?因为存在类型擦除我们在编码时应该注意些什么问题? 详见:https://www.ziwenxie.site/2017/03/01/java-generic/。

【参考】 https://segmentfault.com/a/1190000002646193 Java泛型:泛型类、泛型接口和泛型方法 http://www.jianshu.com/p/b99a40c1f760 浅谈Java泛型

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2017-12-11 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

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

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 什么是范型
  • 范型有什么用途
    • 1. 使用Java集合类时明确指定元素类型
      • 2. 定义泛型类
        • 3. 定义泛型方法
          • 4. 定义泛型接口
          • 使用泛型注意事项
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档