0

0

java之泛型

黄舟

黄舟

发布时间:2017-02-24 09:56:33

|

1258人浏览过

|

来源于php中文网

原创

一、泛型简介

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

二、为什么需要泛型

2.1、编译期对数据类型进行检测

首先我们看一个案例,向一个ArrayList中添加字符串,“不小心”添加了整数,如下面代码,
并没有错误:

这里写图片描述

但是执行时,会报错:java.lang.classCastException”

立即学习Java免费学习笔记(深入)”;

这里写图片描述

因为ArrayList中维护的是一个Object数组, private transient Object[] elementData;
, 使用get()返回的是一个Object对象, 需要强制转换,但是中间混杂一个Integer数值, 导致强制转换失败。这个错误就是由于Object的任意化导致的。
如果能在编译阶段就发现数据类型有错, 那么就很方便,泛型就满足了这个要求:我将这个程序修改一下,ArrayList使用泛型:会发现编译阶段就报错了.
这里写图片描述

2.2强制转换是自动的

不使用泛型:

package com.chb.fanxing;public class NoGen {    
private Object ob;    
public NoGen(Object ob) {        
this.ob = ob;
    }
    getter setter...    
    private void showType() {
        System.out.println("数据的实际类型是:" + ob.getClass().getName());
    }    public static void main(String[] args) {
        NoGen ngInt = new NoGen(88);
        ngInt.showType();        int i = (int)ngInt.getOb();
        System.out.println("value = " + i);
        System.out.println("---------------");

        NoGen ngStr = new NoGen("88");
        ngStr.showType();
        String str = (String)ngStr.getOb();
        System.out.println("value = " + str);   
    }
}

使用泛型:

package com.chb.fanxing;public class Gen {    
private T ob;    
public Gen(T ob) {        
this.ob = ob;
    }
    getter setter...    
    private void showType() {
        System.out.println("T的实际类型:"+ob.getClass().getName());
    }    public static void main(String[] args) {        //定义一个Integer版本
        Gen genInt = new Gen(88);
        genInt.showType();        int i = genInt.getOb();//此处不用强制转换
        System.out.println("value = " + i);
        System.out.println("----------------------");

        Gen genStr = new Gen("88");
        genStr.showType();
        String str = genStr.getOb();
        System.out.println("value = "+str); 
    }
}

运行结果:

两个例子的运行结果是一致的

数据的实际类型是:java.lang.Integervalue = 88
---------------数据的实际类型是:java.lang.String
value = 88

对比两个例子会发现:

  • 使用泛型,强制转换时自动进行的:

int i = genInt.getOb();//此处不用强制转换
  • 而不使用泛型,必须要进行手动强制转化

int i = (int)ngInt.getOb();

三、深入泛型

3.1 、有两个类,我们需要打印他们的成员变量

class StringDemo {    
private String s;    
public StringDemo (String s) {        
this.s = s;
    }
    setter geter....
}
class DoubleDemo{    
private Double d;    
public DoubleDemo(Double d) {        
this.d = d;
    }
    setter getter...
}

3.2、重构

仔细观察两个类功能基本一致,只是数据类型不一样,考虑到重构,因为Object是所有类的基类,所以可以使用Object作为成员变量,这样代码就可以通用了。重构代码如下:

class ObjectDemo{
    private Object ob;    
    public ObjectDemo(Object ob){        
    this.ob = ob;
    }
    setter getter...
}

ObjectDemo测试:

public static void ObjectDemoTest(){
        ObjectDemo strOD = new ObjectDemo("123");
        ObjectDemo dOD = new ObjectDemo(new Double(23));
        ObjectDemo od = new ObjectDemo(new Object());
        System.out.println((String)strOD.getOb());
        System.out.println((Double)dOD.getOb());
        System.out.println(od.getOb());
    }

运行结果:
这里写图片描述

3.3使用泛型重构

发现上面的ObjectDemoTest() 中必须要使用强制转换,这比较麻烦,我们还必须事先知道要转换的数据类型,才能进行正确的转换,否则,会出现错误, 业务编译时没有问题,但是一运行,会出现”classCastException”。所以我们需要不用自己进行强制转换,这是泛型就尤为重要。

class GenDemo{    
private T t;    
public GenDemo(T t) {        
this.t = t;
    } 
    public void setT(T t) {        
    this.t = t;
    }    
    public T getT() {        
    return t;
    }
}

测试:省去了手动进行强制转换

public static void GenTest() {
        GenDemo strOD = new GenDemo("123");
        GenDemo dOD = new GenDemo(new Double(23));
        GenDemo od = new GenDemo(new Object());
        System.out.println(strOD.getT());
        System.out.println(dOD.getT());
        System.out.println(od.getT());
}

下面解释一下上面的泛型语法:

使用表示一个类型持有者名称, 相当于一个形参,数据的类型是有实际传入的数据的类型决定,然后T作为成员、参数、方法的返回值的类型。
T仅仅是一个名字,可以随意取的。
class GenDemo , T没有进行任何限制, 实际相当于 Object,  
等同于 class GenDemo。
与Object相比,使用泛型所定义的类,在定义和声明,可以使用来制定真实的数据类型,如:

GenDemo dOD = new GenDemo(new Double(23));
也可以不指定,那么就需要进行强制转换。

下文我们将继续java的泛型
限制泛型
多接口限制
通配符泛型

Natural Language Playlist
Natural Language Playlist

探索语言和音乐之间丰富而复杂的关系,并使用 Transformer 语言模型构建播放列表。

下载

一、泛型简介

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

二、为什么需要泛型

2.1、编译期对数据类型进行检测

首先我们看一个案例,向一个ArrayList中添加字符串,“不小心”添加了整数,如下面代码,
并没有错误:

这里写图片描述

但是执行时,会报错:“java.lang.classCastException”

这里写图片描述

因为ArrayList中维护的是一个Object数组, private transient Object[] elementData;
, 使用get()返回的是一个Object对象, 需要强制转换,但是中间混杂一个Integer数值, 导致强制转换失败。这个错误就是由于Object的任意化导致的。
如果能在编译阶段就发现数据类型有错, 那么就很方便,泛型就满足了这个要求:我将这个程序修改一下,ArrayList使用泛型:会发现编译阶段就报错了.
这里写图片描述

2.2强制转换是自动的

不使用泛型:

package com.chb.fanxing;public class NoGen {    
private Object ob;    
public NoGen(Object ob) {        
this.ob = ob;
    }
    getter setter...    private void showType() {
        System.out.println("数据的实际类型是:" + ob.getClass().getName());
    }    public static void main(String[] args) {
        NoGen ngInt = new NoGen(88);
        ngInt.showType();        int i = (int)ngInt.getOb();
        System.out.println("value = " + i);
        System.out.println("---------------");

        NoGen ngStr = new NoGen("88");
        ngStr.showType();
        String str = (String)ngStr.getOb();
        System.out.println("value = " + str);   
    }
}

使用泛型:

package com.chb.fanxing;public class Gen {    
private T ob;    
public Gen(T ob) {        
this.ob = ob;
    }
    getter setter...    private void showType() {
        System.out.println("T的实际类型:"+ob.getClass().getName());
    }    public static void main(String[] args) {        //定义一个Integer版本
        Gen genInt = new Gen(88);
        genInt.showType();        int i = genInt.getOb();//此处不用强制转换
        System.out.println("value = " + i);
        System.out.println("----------------------");

        Gen genStr = new Gen("88");
        genStr.showType();
        String str = genStr.getOb();
        System.out.println("value = "+str); 
    }
}

运行结果:

两个例子的运行结果是一致的

数据的实际类型是:java.lang.Integervalue = 88
---------------数据的实际类型是:java.lang.String
value = 88

对比两个例子会发现:

  • 使用泛型,强制转换时自动进行的:

int i = genInt.getOb();//此处不用强制转换
  • 而不使用泛型,必须要进行手动强制转化

int i = (int)ngInt.getOb();

三、深入泛型

3.1 、有两个类,我们需要打印他们的成员变量

class StringDemo {    
private String s;    
public StringDemo (String s) {        
this.s = s;
    }
    setter geter....
}
class DoubleDemo{    
private Double d;    
public DoubleDemo(Double d) {        
this.d = d;
    }
    setter getter...
}

3.2、重构

仔细观察两个类功能基本一致,只是数据类型不一样,考虑到重构,因为Object是所有类的基类,所以可以使用Object作为成员变量,这样代码就可以通用了。重构代码如下:

class ObjectDemo{
    private Object ob;    
    public ObjectDemo(Object ob){        
    this.ob = ob;
    }
    setter getter...
}

ObjectDemo测试:

public static void ObjectDemoTest(){
        ObjectDemo strOD = new ObjectDemo("123");
        ObjectDemo dOD = new ObjectDemo(new Double(23));
        ObjectDemo od = new ObjectDemo(new Object());
        System.out.println((String)strOD.getOb());
        System.out.println((Double)dOD.getOb());
        System.out.println(od.getOb());
    }

运行结果:
这里写图片描述

3.3使用泛型重构

发现上面的ObjectDemoTest() 中必须要使用强制转换,这比较麻烦,我们还必须事先知道要转换的数据类型,才能进行正确的转换,否则,会出现错误, 业务编译时没有问题,但是一运行,会出现”classCastException”。所以我们需要不用自己进行强制转换,这是泛型就尤为重要。

class GenDemo{    private T t;    public GenDemo(T t) {        this.t = t;
    } 
    public void setT(T t) {        this.t = t;
    }    public T getT() {        return t;
    }
}

测试:省去了手动进行强制转换

public static void GenTest() {
        GenDemo strOD = new GenDemo("123");
        GenDemo dOD = new GenDemo(new Double(23));
        GenDemo od = new GenDemo(new Object());
        System.out.println(strOD.getT());
        System.out.println(dOD.getT());
        System.out.println(od.getT());
}

下面解释一下上面的泛型语法:

使用表示一个类型持有者名称, 相当于一个形参,数据的类型是有实际传入的数据的类型决定,然后T作为成员、参数、方法的返回值的类型。
T仅仅是一个名字,可以随意取的。
class GenDemo , T没有进行任何限制, 实际相当于 Object,  
等同于 class GenDemo。
与Object相比,使用泛型所定义的类,在定义和声明,可以使用来制定真实的数据类型,如:

GenDemo dOD = new GenDemo(new Double(23));
也可以不指定,那么就需要进行强制转换。

 以上就是java之泛型的内容,更多相关内容请关注PHP中文网(www.php.cn)!

相关文章

java速学教程(入门到精通)
java速学教程(入门到精通)

java怎么学习?java怎么入门?java在哪学?java怎么学才快?不用担心,这里为大家提供了java速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
全国统一发票查询平台入口合集
全国统一发票查询平台入口合集

本专题整合了全国统一发票查询入口地址合集,阅读专题下面的文章了解更多详细入口。

19

2026.02.03

短剧入口地址汇总
短剧入口地址汇总

本专题整合了短剧app推荐平台,阅读专题下面的文章了解更多详细入口。

27

2026.02.03

植物大战僵尸版本入口地址汇总
植物大战僵尸版本入口地址汇总

本专题整合了植物大战僵尸版本入口地址汇总,前往文章中寻找想要的答案。

15

2026.02.03

c语言中/相关合集
c语言中/相关合集

本专题整合了c语言中/的用法、含义解释。阅读专题下面的文章了解更多详细内容。

3

2026.02.03

漫蛙漫画网页版入口与正版在线阅读 漫蛙MANWA官网访问专题
漫蛙漫画网页版入口与正版在线阅读 漫蛙MANWA官网访问专题

本专题围绕漫蛙漫画(Manwa / Manwa2)官网网页版入口进行整理,涵盖漫蛙漫画官方主页访问方式、网页版在线阅读入口、台版正版漫画浏览说明及基础使用指引,帮助用户快速进入漫蛙漫画官网,稳定在线阅读正版漫画内容,避免误入非官方页面。

13

2026.02.03

Yandex官网入口与俄罗斯搜索引擎访问指南 Yandex中文登录与网页版入口
Yandex官网入口与俄罗斯搜索引擎访问指南 Yandex中文登录与网页版入口

本专题汇总了俄罗斯知名搜索引擎 Yandex 的官网入口、免登录访问地址、中文登录方法与网页版使用指南,帮助用户稳定访问 Yandex 官网,并提供一站式入口汇总。无论是登录入口还是在线搜索,用户都能快速获取最新稳定的访问链接与使用指南。

114

2026.02.03

Java 设计模式与重构实践
Java 设计模式与重构实践

本专题专注讲解 Java 中常用的设计模式,包括单例模式、工厂模式、观察者模式、策略模式等,并结合代码重构实践,帮助学习者掌握 如何运用设计模式优化代码结构,提高代码的可读性、可维护性和扩展性。通过具体示例,展示设计模式如何解决实际开发中的复杂问题。

3

2026.02.03

C# 并发与异步编程
C# 并发与异步编程

本专题系统讲解 C# 异步编程与并发控制,重点介绍 async 和 await 关键字、Task 类、线程池管理、并发数据结构、死锁与线程安全问题。通过多个实战项目,帮助学习者掌握 如何在 C# 中编写高效的异步代码,提升应用的并发性能与响应速度。

2

2026.02.03

Python 强化学习与深度Q网络(DQN)
Python 强化学习与深度Q网络(DQN)

本专题深入讲解 Python 在强化学习(Reinforcement Learning)中的应用,重点介绍 深度Q网络(DQN) 及其实现方法,涵盖 Q-learning 算法、深度学习与神经网络的结合、环境模拟与奖励机制设计、探索与利用的平衡等。通过构建一个简单的游戏AI,帮助学习者掌握 如何使用 Python 训练智能体在动态环境中作出决策。

3

2026.02.03

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Kotlin 教程
Kotlin 教程

共23课时 | 3.2万人学习

C# 教程
C# 教程

共94课时 | 8.4万人学习

Java 教程
Java 教程

共578课时 | 56.7万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号