前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java基础系列(三十四):泛型入门

Java基础系列(三十四):泛型入门

作者头像
山禾说
发布2019-01-21 10:12:42
3200
发布2019-01-21 10:12:42
举报
文章被收录于专栏:Vi的技术博客Vi的技术博客

为什么需要泛型

使用泛型机制编写的代码要比那些杂乱的使用Object变量,然后再进行强制类型转换的代码具有更好的安全性和可读性,也就是说使用泛型机制编写的代码可以被很多不同类型的对象所重用。

我们先来看看泛型程序设计的机制是如果演变的,这样可以让我们对泛型的作用有一个更深的认识。

泛型的演变

实际上在Java增加泛型机制之前就已经有一个ArrayList类,这个ArrayList类的泛型概念是使用继承来实现的。

代码语言:javascript
复制
public class ArrayList {
    private Object[] elementData;
    public Object get(int i) {....}
    public void add(Object o) {....}
}

这个类存在两个问题:

当获取一个值的时候必须进行强制类型转换

代码语言:javascript
复制
ArrayList files = new ArrayList();
String filename = (String)files.get(0);

没有错误检查,可以向数组中添加任何类的对象

代码语言:javascript
复制
files.add(new File(""));

对于这个调用,编译和运行都不会出错,但是当我们在其他地方使用get方法获取刚刚存入的这个File对象强转为String类型的时候就会产生一个错误。

泛型对于这种问题的解决方案是提供一个类型参数。

代码语言:javascript
复制
ArrayList<String> files = new ArrayList<String>();
//在JavaSE 7及以后的版本中,构造函数可以省略泛型类型:
ArrayList<String> files = new ArrayList<>();

这样可以使代码具有更好的可读性,我们一看就知道这个数据列表中包含的是String对象。 编译器也可以很好地利用这个信息,当我们调用get的时候,不需要再使用强制类型转换,编译器就知道返回值类型为String,而不是Object

代码语言:javascript
复制
String filename = files.get(0);

编译器还知道ArrayList<String>add方法中有一个类型为String的参数。这将比使用Object类型的参数安全一些,现在编译器可以检查,避免插入错误类型的对象:

代码语言:javascript
复制
files.add(new File(""));

这样的代码是无法通过编译的,出现编译错误比类在运行时出现类的强制类型转换异常要好得多。

泛型类

一个泛型类就是具有一个或多个类型变量的类,对于这个类来说,我们只关注泛型,而不会为数据存储的细节烦恼。

代码语言:javascript
复制
public class Pair<T> {
   private T first;
   private T second;

   public Pair() { first = null; second = null; }
   public Pair(T first, T second) { 
        this.first = first;  
        this.second = second; 
   }

   public T getFirst() { return first; }
   public T getSecond() { return second; }

   public void setFirst(T newValue) { first = newValue; }
   public void setSecond(T newValue) { second = newValue; }}

Pair类引入了一个类型变量T,用尖括号括起来,并放在类名的后面。泛型类可以有多个类型变量:

代码语言:javascript
复制
public class Pair<T, U> {...}

类定义中的类型变量是指定方法的返回类型以及域和局部变量的类型

代码语言:javascript
复制
//域
private T first;
//返回类型
public T getFirst() { return first; }
//局部变量
public void setFirst(T newValue) { 
    first = newValue; 
}

类型变量使用大写形式,且比较短,这是很常见的,在Java库中,使用变量E表示集合的元素类型,KV分别表示表的关键字与值得类型。T表示“任意类型”。 使用具体的类型代替类型变量就可以实例化泛型类型:

代码语言:javascript
复制
Pair<String>

可以将结果想象成带有构造器的普通类:

代码语言:javascript
复制
Pair<String>()
Pair<String>(String, String)

和方法

代码语言:javascript
复制
String getFirst();
String getSecond();
void setFirst(String);
void setSecond(String);

泛型类可以看成是普通类的工厂

泛型方法

首先我们来看一个泛型方法的实例:

代码语言:javascript
复制
class ArrayAlg {
    public static <T> T getMiddle(T...a){
        return a[a.length / 2];
    }
}

首先,这个方法是在普通类中定义的,而不是在泛型类中定义的。然而,这是一个泛型方法,可以从尖括号和类型变量看出这一点。注意,类型变量是放在修饰符的后面返回类型的前面。 泛型方法可以定义在普通类中,也可以定义在泛型类中。 当调用一个泛型方法时,在方法名前的尖括号中放入具体的类型:

代码语言:javascript
复制
String middle = ArrayAlg.<String>getMiddle("a","b","c");

在这种情况下,方法调用中可以省略<String>类型参数,编译器会使用类型推断来推断出所调用的方法,也就是说可以这么写:

代码语言:javascript
复制
String middle = ArrayAlg.getMiddle("a","b","c");
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2018-09-21,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Vi的技术博客 微信公众号,前往查看

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

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 泛型类
相关产品与服务
数据保险箱
数据保险箱(Cloud Data Coffer Service,CDCS)为您提供更高安全系数的企业核心数据存储服务。您可以通过自定义过期天数的方法删除数据,避免误删带来的损害,还可以将数据跨地域存储,防止一些不可抗因素导致的数据丢失。数据保险箱支持通过控制台、API 等多样化方式快速简单接入,实现海量数据的存储管理。您可以使用数据保险箱对文件数据进行上传、下载,最终实现数据的安全存储和提取。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档