Java泛型初探
前言
在学习java掉头的日子里很多青年脱坑,同时也有很多青年入坑,但入坑的时候可能没有什么好的指导或者学习方法可能头发掉的一发不可收拾……
笔者有个学弟就遇到了相同的境遇,学弟被泛型搞得头晕目眩,搞不懂泛型是个啥玩意。天天用的泛型也不知道啥玩意(他可能都不知道他有没有用泛型)。立图为证!当然,笔者深度还欠缺,如果错误还请指正!
本篇就根据笔者的理解简单的介绍一下泛型(深入还需自己),如果深度不够或者有错误还请见谅。
泛型是程序设计语言的一种特性。允许程序员在强类型程序设计语言中编写代码时定义一些可变部分,那些部分在使用前必须作出指明。各种程序设计语言和其编译器、运行环境对泛型的支持均不一样。将类型参数化以达到代码复用提高软件开发工作效率的一种数据类型。泛型类是引用类型,是堆对象,主要是引入了类型参数这个概念。
——百度百科
没有泛型的时候
泛型,从字面的意思来看,广泛的意思,能够广泛的代表或者处理某一类事务的类型(java集合类)。在没有泛型的时候,你会如何去处理?比如你写链表的时候。可能会这样:
public class node { public int value;//节点的结果 node next;//下一个连接的节点 public node(){} public node(int value) { this.value=value; } }
这个node 节点存的是int类型,如果是存一个字符串的链表或者是一个double类型数据链表呢?难道要这样重复的写:
public class node { public String value;//节点的结果 node next;//下一个连接的节点 public node(){} public node(String value) { this.value=value; } }
- 重写?你去重写吧。
使用Object类表示泛型
发现在设计上存在的这个大问题之后,大大纷纷考虑到这种问题的严重和复杂性,随着面向对象的发展流行我们知道在java中有向上转型和向下转型.
向上转型:将子类对象赋值给父类类型的变量,这种技术称为向上转型。可以在父类中定义方法,然后根据子类中具体实现这样也正是多态机制的基本思想。
因为很多时候我们不一定使用类越细越好,比如狗的共同点已经很相似了,一群狗我们可能使用dog来表示操作它们,但是在实例化可能根据哈士奇、藏獒、金毛等不同种类具体实例化。重写部分特殊函数,在使用的时候直接使用dog的api即可满足要求。
在java中这种多态思想也非常多,比如类似以下:
List<Integer>list1=new ArrayList<Integer>(); List<Integer>list2=new LinkedList<Integer>();
前面的向上转型是更具体的类转为较为抽象的类。谈完向上转型,当然还有个向下转型啦,向下转型就是将较抽象的类转换为较具体的类。当然向下转型需要强制类型转换(显示转换告诉编译器)
如果使用代码来看:
public class test { public static void main(String[] args) { //animal指想dog的堆地址,向上转型 从 dog——》animal 向上父类转 animal animal=new dog("doudou",17); //dog 指想animal指想的地址,从 anmial——》dog为向下子类转 dog dog=(dog)animal; animal.sayhello(); dog.sayhello(); } } class animal { public String name; public int age; public animal(String name,int age){ this.name=name; this.age=age; } public void sayhello() { System.out.println("hello,我是aninal"+this.name+"今年"+this.age+"岁"); } } class dog extends animal { public dog(String name, int age) { super(name, age); } @Override public void sayhello() { System.out.println("hello,我是狗狗"+this.name+"今年"+age+"岁"); } }
我们知道在java中Object类为所有类的父类(超类)。它是站在最顶端的类型,所有类(class)都是它的子子孙孙,它自己写好了toString(),equalls()等方法。
而同理我们借鉴这种思想可以将一个类先向上转型成Object类,然后再将操作完的数向下转型成我们所需要的数。达到这种使用上的效果,但是基本类型无法满足这个要求啊,所以就出现了包装类这个东西。在储存对象时候一定程度上能够满足使用需求。
public class test { public static void main(String[] args) { Integer a=10; node node1=new node(a); Integer va1=(Integer) node1.getValue(); System.out.println(va1); node node2=new node("hello"); String va2=(String) node2.getValue(); System.out.println(va2); } } class node { private Object value; public node(Object value) { this.value=value; } public Object getValue() { return value; } public void setValue(Object value) { this.value = value; } }
执行的结果为:
10 hello
这种虽然一定程度能够达到泛型效果,但是除了功能受限、使用麻烦之外,还有个更大的毛病。就是在第二次显示的向下转向的时候,如果人为转换错误编译器无法识别,而必须等到代码执行时候才报错,这样的机制让java代码变得不太安全。
Java泛型
在Object显示转换存在不安全行为的情况下,Java在jdk1.5以后提出了泛型机制,通过泛型就能有效避免转型时候出现的问题,泛型简单的理解就是在类、接口、方法中定义未知类型变量,只有初始化的时候才知道真正的类型。在定义的类或接口函数中可以直接使用这个未知类型进行操作。
泛型类
泛型类的语法如下:
类名<T> 其中T代表一个类型名称 类名<T1,T2> 可能有多个类型
其中T,T1,T2都叫做通配符。常用的通配符有T,E,K,V分别表示类型、元素、键、值,当然这并不是硬性规定,而是大家形成的一种通识。
你在创建node类就可以使用如下的写法了:
public class node <T>{ private T value; public node(T value) { this.value = value; } public T getValue() { return value; } public void setValue(T value) { this.value = value; } }
其中T就可以在类中自由使用,这个类我们暂时不知道是什么,但是初始化的时候编译器就知道它是什么类型:
泛型接口
既然类可以使用泛型,接口当然也可以,不过接口使用泛型和普通类的略有区别,子类在继承泛型接口的时候需要接口处声明泛型类型,否则编译器报错。例如下面的pig类。
而如果你依然想在子类中使用泛型,那就需要在子类中声明一个泛型,而接口中的泛型使用子类的泛型类型。例如下面的dog类。
interface aninal <T> { T getValue(T t); } class cat implements aninal {//用默认Object类型 @Override public Object getValue(Object o) { return o; } } class pig implements aninal<String>{//子类不设置泛型,父类接口的泛型需要明确类型 @Override public String getValue(String s) { return s+"哼哼"; } } class dog <T>implements aninal<T> {//子类和接口均使用泛型。 @Override public T getValue(T t) { return t; } }
也就是说使用泛型接口如果进行继承依然想使用泛型就需要在继承的类中事先定义好接口部分的泛型类供接口使用。
class 类 <A,B,C>implements aninal<C>
泛型方法
泛型函数的基本使用也很容易,和泛型类和泛型接口使用很相似,不过就是菱形需要放到函数类型前面:
public <T1,T2> void fuc(T1 t1,T2 t2) { System.out.println(t1); System.out.println(t2); }
边界限定
泛型既然这么好用,可以在使用时候直接传入具体类型,但是我们在开发很多时候某个类或者某个方法的能够传入类型是有限制的。那么在java中有上边界限定和下边界限定用来限制泛型的可用类型。
限定通配符包括两种:
- 类型的上界,格式为:<? extends T>,即类型必须为T类型或者T子类
- 类型的下界,格式为:<? super T>,即类型必须为T类型或者T的父类
举个例子在Java中编写这些类和方法:
class animal { //dosomething } class dog extends animal { //dosomething } class pig extends animal { //dosomething } public class test { static void printlist1(List<? extends animal>list)//只能aninal和animal的子类 { for(animal animal:list) { System.out.println(animal); } } static void dolist2(List<? super pig>list) { //dosomething } }
这样printlist1函数就使用了上边界限定。而dolist2函数就用了泛型的下边界限定,当你错误运用时候编译器就可以提示出来。
尾声
当然本篇并不是一个完整的泛型解答和总结,泛型还有很多细致的需要对比其差别这里就先不介绍啦。
从整体来讲,泛型的主要作用还是为了解决类型转换的安全性问题,避免了Object来回转换的问题,使得编译器就能识别类型转换的错误,同时通过限定类型使得函数方法等使用的更加灵活方便。不过泛型更多的应用于框架的编写方面,在java中其实也是随处可见。尤其是集合类:
看了这篇泛型,下次设计链表二叉树别傻傻的用int 表示node节点的值了!我想你该知道正确的写法了!
笔者微信公众号:bigsai
更多学习资料、精彩内容与你分享!

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
一篇文章教会你用Python多线程获取小米应用商店App
【一、项目背景】 小米应用商店给用户发现最好的安卓应用和游戏,安全可靠,可是要下载东西要一个一个的搜索太麻烦了。而已速度不是很快。 今天用多线程爬取小米应用商店的游戏模块。快速获取。 【二、项目目标】 目标 :应用分类 - 聊天社交 应用名称, 应用链接,显示在控制台供用户下载。 【三、涉及的库和网站】 1、网址:百度搜 - 小米应用商店,进入官网。 2、涉及的库:requests、threading 、queue 、json、time 3、软件:PyCharm 【四、项目分析】 1、确认是否为动态加载。 通过页面局部刷新, 右键查看网页源代码,搜索关键字未搜到 。断定此网站为动态加载网站,需要抓取网络数据包分析。 2、使用chrome浏览器,F12抓取网络数据包。 1)抓取返回json数据的URL地址(Headers中的Request URL)。 http://app.mi.com/categotyAllListApi?page={}&categoryId=2&pageSize=30 2)查看并分析查询参数(headers中的Query String Paramete...
- 下一篇
JDBC+MySQL实战
前言 hello我是bigsai,今天咱们进行JDBC+MySQL实战,非常适合初入门的小伙伴打开新的世界。实现一个增删改查(curd)的例子。有用的话先点赞再观看、帅哥靓女养成好习惯!没用再把小赞赞回收也不迟嘿嘿 在这个案例进行之前,你要确保自己电脑上拥有MySQL和IDEA编译器,另外还要安装MySQL数据库连接管理工具Navicat。方能进行以下的操作。 如果以前没见过或者使用过也不要紧,本课程提供傻瓜式教学你只需跟着我的要求来包成功包会。 通过本翩你可以掌握以下内容: MySQL数据库的创建 JDBC+MySQL项目的创建 JDBC成功对MySQL增删改查 案例分析 本次案例到底是个什么结果呢?本案例实现一个学生信息的管理,即学生个人信息的增删改查。 核心思路拆解 我们该如何设计这个项目呢? 别急别急,听我慢慢说道。对于本案例的实战,旨在实现用Java语言(JDBC)操作MySQL,核心的主轴是MySQL的数据,所以我们从MySQL为起始点入手,整个案例实现的流程大致可以分为: 分析设计需求、创建MySQL数据库和表 创建Java项目,添加JDBC以及Junit单元测试的依赖 ...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- SpringBoot2更换Tomcat为Jetty,小型站点的福音
- Windows10,CentOS7,CentOS8安装MongoDB4.0.16
- SpringBoot2整合Thymeleaf,官方推荐html解决方案
- SpringBoot2整合Redis,开启缓存,提高访问速度
- CentOS8安装MyCat,轻松搞定数据库的读写分离、垂直分库、水平分库
- CentOS7安装Docker,走上虚拟化容器引擎之路
- CentOS7设置SWAP分区,小内存服务器的救世主
- SpringBoot2编写第一个Controller,响应你的http请求并返回结果
- MySQL8.0.19开启GTID主从同步CentOS8
- Hadoop3单机部署,实现最简伪集群