出自:https://mp.weixin.qq.com/s/xguhv0qRg2sZAW3mhMHX7w

前言

从今天开始进入Java基础的复习,可能一个星期会有一篇的,我写博文的未必都是正确的~如果有写错的地方请大家多多包涵并指正~

今天要复习的是泛型,泛型在Java中也是个很重要的知识点,本文主要讲解基础的概念,并不是高深的知识,如果基础好的同学可以当复习看看~

一、什么是泛型?

Java泛型设计原则:只要在编译时期没有出现警告,那么运行时期就不会出现ClassCastException异常.

泛型:把类型明确的工作推迟到创建对象或调用方法的时候才去明确的特殊的类型

参数化类型:

  • 把类型当作是参数一样传递
  • 只能是引用类型

相关术语:

  • ArrayList中的E称为类型参数变量
  • ArrayList中的Integer称为实际类型参数
  • 整个称为ArrayList泛型类型
  • 整个ArrayList称为参数化的类型ParameterizedType

二、为什么需要泛型

早期Java是使用Object来代表任意类型的,但是向下转型有强转的问题,这样程序就不太安全

首先,我们来试想一下:没有泛型,集合会怎么样

  • Collection、Map集合对元素的类型是没有任何限制的。本来我的Collection集合装载的是全部的Dog对象,但是外边把Cat对象存储到集合中,是没有任何语法错误的。
  • 把对象扔进集合中,集合是不知道元素的类型是什么的,仅仅知道是Object。因此在get()的时候,返回的是Object。外边获取该对象,还需要强制转换

有了泛型以后:

  • 代码更加简洁【不用强制转换】
  • 程序更加健壮【只要编译时期没有警告,那么运行时期就不会出现ClassCastException异常】
  • 可读性和稳定性【在编写集合的时候,就限定了类型】

2.1有了泛型后使用增强for遍历集合

在创建集合的时候,我们明确了集合的类型了,所以我们可以使用增强for来遍历集合!

 //创建集合对象 ArrayList list = new ArrayList<>(); list.add("hello"); list.add("world"); list.add("java"); //遍历,由于明确了类型.我们可以增强for for (String s : list) { System.out.println(s); }

三、泛型基础

3.1泛型类

泛型类就是把泛型定义在类上,用户使用该类的时候,才把类型明确下来….这样的话,用户明确了什么类型,该类就代表着什么类型…用户在使用的时候就不用担心强转的问题,运行时转换异常的问题了。

  • 在类上定义的泛型,在类的方法中也可以使用!
/* 1:把泛型定义在类上 2:类型变量定义在类上,方法中也可以使用 */public class ObjectTool { private T obj; public T getObj() { return obj; } public void setObj(T obj) { this.obj = obj; }}
  • 测试代码:

用户想要使用哪种类型,就在创建的时候指定类型。使用的时候,该类就会自动转换成用户想要使用的类型了。

 public static void main(String[] args) { //创建对象并指定元素类型 ObjectTool tool = new ObjectTool<>(); tool.setObj(new String("钟福成")); String s = tool.getObj(); System.out.println(s); //创建对象并指定元素类型 ObjectTool objectTool = new ObjectTool<>(); /** * 如果我在这个对象里传入的是String类型的,它在编译时期就通过不了了. */ objectTool.setObj(10); int i = objectTool.getObj(); System.out.println(i); }

3.2泛型方法

前面已经介绍了泛型类了,在类上定义的泛型,在方法中也可以使用…..

现在呢,我们可能就仅仅在某一个方法上需要使用泛型….外界仅仅是关心该方法,不关心类其他的属性…这样的话,我们在整个类上定义泛型,未免就有些大题小作了。

  • 定义泛型方法….泛型是先定义后使用的
 //定义泛型方法.. public  void show(T t) { System.out.println(t); }
  • 测试代码:

用户传递进来的是什么类型,返回值就是什么类型了

 public static void main(String[] args) { //创建对象 ObjectTool tool = new ObjectTool(); //调用方法,传入的参数是什么类型,返回值就是什么类型 tool.show("hello"); tool.show(12); tool.show(12.5); }

3.3泛型类派生出的子类

前面我们已经定义了泛型类,泛型类是拥有泛型这个特性的类,它本质上还是一个Java类,那么它就可以被继承

那它是怎么被继承的呢??这里分两种情况

  1. 子类明确泛型类的类型参数变量
  2. 子类不明确泛型类的类型参数变量

3.3.1子类明确泛型类的类型参数变量

  • 泛型接口
/* 把泛型定义在接口上 */public interface Inter { public abstract void show(T t);}
  • 实现泛型接口的类…..
/** * 子类明确泛型类的类型参数变量: */public class InterImpl implements Inter { @Override public void show(String s) { System.out.println(s); }}

3.3.2子类不明确泛型类的类型参数变量

  • 当子类不明确泛型类的类型参数变量时,外界使用子类的时候,也需要传递类型参数变量进来,在实现类上需要定义出类型参数变量
/** * 子类不明确泛型类的类型参数变量: * 实现类也要定义出类型的 * */public class InterImpl implements Inter { @Override public void show(T t) { System.out.println(t); }}

测试代码:

 public static void main(String[] args) { //测试第一种情况 //Inter i = new InterImpl(); //i.show("hello"); //第二种情况测试 Inter ii = new InterImpl<>(); ii.show("100"); }

值得注意的是:

  • 实现类的要是重写父类的方法,返回值的类型是要和父类一样的!
  • 类上声明的泛形只对非静态成员有效

3.4类型通配符

为什么需要类型通配符????我们来看一个需求…….

现在有个需求:方法接收一个集合参数,遍历集合并把集合元素打印出来,怎么办?

  • 按照我们没有学习泛型之前,我们可能会这样做:
public void test(List list){ for(int i=0;i

上面的代码是正确的,只不过在编译的时候会出现警告,说没有确定集合元素的类型….这样是不优雅的…

那我们学习了泛型了,现在要怎么做呢??有的人可能会这样做:

public void test(List list){ for(int i=0;i

这样做语法是没毛病的,但是这里十分值得注意的是:该test()方法只能遍历装载着Object的集合!!!

强调:泛型中的并不是像以前那样有继承关系的,也就是说List和List是毫无关系的!!!!

那现在咋办???我们是不清楚List集合装载的元素是什么类型的,List这样是行不通的……..于是Java泛型提供了类型通配符 ?

所以代码应该改成这样:

public void test(List> list){ for(int i=0;i

?号通配符表示可以匹配任意类型,任意的Java类都可以匹配…..

现在非常值得注意的是,当我们使用?号通配符的时候:就只能调对象与类型无关的方法,不能调用对象与类型有关的方法。

记住,只能调用与对象无关的方法,不能调用对象与类型有关的方法。因为直到外界使用才知道具体的类型是什么。也就是说,在上面的List集合,我是不能使用add()方法的。因为add()方法是把对象丢进集合中,而现在我是不知道对象的类型是什么。

3.4.1设定通配符上限

首先,我们来看一下设定通配符上限用在哪里….

现在,我想接收一个List集合,它只能操作数字类型的元素【Float、Integer、Double、Byte等数字类型都行】,怎么做???

我们学习了通配符,但是如果直接使用通配符的话,该集合就不是只能操作数字了。因此我们需要用到设定通配符上限

 List extends Number>

上面的代码表示的是:List集合装载的元素只能是Number的子类或自身

 public static void main(String[] args) { //List集合装载的是Integer,可以调用该方法 List integer = new ArrayList<>(); test(integer); //List集合装载的是String,在编译时期就报错了 List strings = new ArrayList<>(); test(strings); } public static void test(List extends Number> list) { }

3.4.2设定通配符下限

既然上面我们已经说了如何设定通配符的上限,那么设定通配符的下限也不是陌生的事了。直接来看语法吧

 //传递进来的只能是Type或Type的父类  super Type>

设定通配符的下限这并不少见,在TreeSet集合中就有….我们来看一下

 public TreeSet(Comparator super E> comparator) { this(new TreeMap<>(comparator)); }

那它有什么用呢??我们来想一下,当我们想要创建一个TreeSet类型的变量的时候,并传入一个可以比较String大小的Comparator。

那么这个Comparator的选择就有很多了,它可以是Comparator,还可以是类型参数是String的父类,比如说Comparator….

这样做,就非常灵活了。也就是说,只要它能够比较字符串大小,就行了

值得注意的是:无论是设定通配符上限还是下限,都是不能操作与对象有关的方法,只要涉及到了通配符,它的类型都是不确定的!

3.5通配符和泛型方法

大多时候,我们都可以使用泛型方法来代替通配符的…..

 //使用通配符 public static void test(List> list) { } //使用泛型方法 public  void test2(List t) { }

上面这两个方法都是可以的…..那么现在问题来了,我们使用通配符还是使用泛型方法呢??

原则:

如果参数之间的类型有依赖关系,或者返回值是与参数之间有依赖关系的。那么就使用泛型方法如果没有依赖关系的,就使用通配符,通配符会灵活一些.

3.6泛型擦除

泛型是提供给javac编译器使用的,它用于限定集合的输入类型,让编译器在源代码级别上,即挡住向集合中插入非法数据。但编译器编译完带有泛形的java程序后,生成的class文件中将不再带有泛形信息,以此使程序运行效率不受到影响,这个过程称之为“擦除”。

3.6.1兼容性

JDK5提出了泛型这个概念,但是JDK5以前是没有泛型的。也就是泛型是需要兼容JDK5以下的集合的。

当把带有泛型特性的集合赋值给老版本的集合时候,会把泛型给擦除了。

值得注意的是:它保留的就类型参数的上限。

 List list = new ArrayList<>(); //类型被擦除了,保留的是类型的上限,String的上限就是Object List list1 = list;

如果我把没有类型参数的集合赋值给带有类型参数的集合赋值,这又会怎么样??

 List list = new ArrayList(); List list2 = list;

它也不会报错,仅仅是提示“未经检查的转换”

四、泛型的应用

当我们写网页的时候,常常会有多个DAO,我们要写每次都要写好几个DAO,这样会有点麻烦。

这里写图片描述

那么我们想要的效果是什么呢??只写一个抽象DAO,别的DAO只要继承该抽象DAO,就有对应的方法了。

要实现这样的效果,肯定是要用到泛型的。因为在抽象DAO中,是不可能知道哪一个DAO会继承它自己,所以是不知道其具体的类型的。而泛型就是在创建的时候才指定其具体的类型。

抽象DAO

public abstract class BaseDao { //模拟hibernate.... private Session session; private Class clazz; //哪个子类调的这个方法,得到的class就是子类处理的类型(非常重要) public BaseDao(){ Class clazz = this.getClass(); //拿到的是子类 ParameterizedType pt = (ParameterizedType) clazz.getGenericSuperclass(); //BaseDao clazz = (Class) pt.getActualTypeArguments()[0]; System.out.println(clazz); } public void add(T t){ session.save(t); } public T find(String id){ return (T) session.get(clazz, id); } public void update(T t){ session.update(t); } public void delete(String id){ T t = (T) session.get(clazz, id); session.delete(t); }}

继承抽象DAO,该实现类就有对应的增删改查的方法了。

CategoryDao

public class CategoryDao extends BaseDao {}

BookDao

public class BookDao extends BaseDao {}

五、最后

泛型的基础就介绍到这里了,如果以后有需要的话再进行深入研究吧~如果觉得该文章帮助到你,不妨点个赞,关注公众号一波~

参考资料:

Core Java

微信公众号【程序员乔戈里】 作者乔戈里,斜杠青年,哈工大本硕985 硕士,百度Java 研发工程师,目前致力于分享求职必备学习经验、求职心得和成长感悟/技术文章。(关注公众号送9000G 考研/python/C++/java/前端/小程序/微信公众号/机器学习/人工智能资源)

不能使用泛型的形参创建对象_泛型就这么简单相关推荐

  1. 不能使用泛型的形参创建对象_数据类型之----泛型

    泛型 泛型:可以在类或方法中预支地使用未知的类型. 一般在创建对象时,将未知的类型确定具体的类型.当没有指定泛型时,默认类型为Object类型. 使用泛型的好处 <1>将运行时期的Clas ...

  2. 复习Collection_迭代器使用细节_泛型_综合案例

    Collection_迭代器使用细节_泛型_综合案例 主要内容 Collection集合 迭代器 增强for 泛型 第一章 Collection集合 1.1 集合概述 集合:集合是java中提供的一种 ...

  3. 泛型方法的定义和使用_泛型( Generic )

    泛型(Generic) 1. 泛型概述 泛型是一个未知的, 不确定的数据类型. 比如ArrayList 中的E, 就是一个未知的不确定的数据类型, 那么他就是一个泛型 泛型虽然是一个未知的, 不确定的 ...

  4. 4_常用类_集合_泛型

    JavaSE_第四周 包装类 基本类型 包装类类型(引用类型:默认值都是null) byte Byte short Short int Integer long Long float Float do ...

  5. java泛型有什么用_什么叫泛型?有什么作用?

    一.什么是泛型? Java泛型设计原则:只要在编译时期没有出现警告,那么运行时期就不会出现ClassCastException异常. 泛型:把类型明确的工作推迟到创建对象或调用方法的时候才去明确的特殊 ...

  6. Java千百问_05面向对象(012)_泛型是什么

    1.什么是泛型 泛型是Java SE 1.5的新特性,泛型即参数化类型,也就是说所操作的数据类型被指定为一个参数.  这种参数类型可以用在类.接口和方法的创建中,分别称为泛型类.泛型接口.泛型方法.  ...

  7. java泛型一定用包装类_你不知道的基本数据类型和包装类

    你不知道的基本数据类型和包装类 基本数据类型 Java 基本数据按类型可以分为四大类:布尔型.整数型.浮点型.字符型,这四大类包含 8 种基本数据类型.布尔型:boolean 整数型:byte.sho ...

  8. SCJP笔记_章七_泛型与集合

    第七章 泛型与集合 7.1 重写hashCode()和equals()方法 考试目标6.2 区分hashCode()和equals()方法的正确设计和错误设计,并解释 == 和equals()方法的不 ...

  9. java 泛型使用场景_泛型的使用场景,可以作用在什么位置,使用泛型有什么好处...

    1.什么是泛型,泛型有什么用,为什么要用 1.1 泛型就是一种未知的类,将未知的类型声明在集合.对象上,泛型的默认类型为Object. 例如: ArrayList str = new ArrayLis ...

  10. 泛型java 代码讲解_Java泛型详解

    2516326-5475e88a458a09e4.png 一,打破砂锅问到底 泛型存在的意义? 泛型类,泛型接口,泛型方法如何定义? 如何限定类型变量? 泛型中使用的约束和局限性有哪些? 泛型类型的继 ...

最新文章

  1. Nginx之简介与安装(一)
  2. oracle如何计算2个坐标的距离,百度地图两个坐标之间的距离计算
  3. mac 如何查看anaconda的路径_Mac OS如何直接查看gif图片?分享MAC直接查看gif图片的三种方法...
  4. Java必会的基础知识(3)
  5. JavaScript入门(part6)--运算符
  6. 1、Hive原理及查询优化
  7. [PAT乙级]1047 编程团体赛
  8. matlab 联合体,C++11非受限联合体(union)
  9. matlab模拟调制过程,模拟信号的调制方式有哪三种?调制与解调是个啥过程
  10. Eclipse无法修改字体
  11. matlab 相位谱_电气信息类专业课程之matlab系统仿真 第九章 提高仿真能力需要案例(1)...
  12. 苹果ios、ipad加密视频播放器使用教程
  13. 【已解决】map container is already initialized——页面切换瓦片图不出来的问题
  14. Java从入门到放弃 --没放弃就写java程序员职业规划
  15. 西安理工大学计算机科学与技术分数线,2017西安理工大学各专业录取分数线
  16. 《互联网周刊》:移动学习在路上
  17. docker minio部署作为shareX截图软件的图床
  18. 移动硬盘无法访问设备未就绪资料找到的法子
  19. 博仲兴业力作——《爱的雨季》讲述爱情的奥秘
  20. 新版HyperMesh的Assemblies中调出下拉菜单查看Component(装配关系模型树)

热门文章

  1. 《转》python学习(3)
  2. javaMail简介(一)
  3. PYTHON之路(九)
  4. onclick获取当前节点
  5. 项目经理的三个立足点
  6. POI动态下载Excel模板案例
  7. RabbitMQ的工作模式及消息顺序性的保证
  8. Java实现单链表翻转
  9. 中国工业机器人市场正在迎来爆发式增长
  10. 浅析Vue源码(二)—— initMixin(上)