泛型(Generic)

1. 泛型概述

  • 泛型是一个未知的, 不确定的数据类型. 比如ArrayList 中的E, 就是一个未知的不确定的数据类型, 那么他就是一个泛型
  • 泛型虽然是一个未知的, 不确定的数据类型, 但他不是一直未知, 一直不确定当我们使用这个类的时候, 会指定这个泛型的类型. 比如ArrayList , ArrayList
  • 泛型可以省略, 如果泛型省略, 相当于泛型是Object. 如ArrayLIst list = new ArrayList();这样的话就可以放任何类型的数据.
  • 泛型也是语法糖, 下面会用例子介绍
package drafts.drafts10;import java.util.ArrayList;public class GenericTest {public static void main(String[] args) {//不适用泛型ArrayList list = new ArrayList();//list.add(100);编译时不报错, 运行时报错list.add("hello");list.add("world");list.add("java");for (Object obj : list) {String str = (String) obj;System.out.println(str.length());}//使用泛型ArrayList<String> list2 = new ArrayList<>();//list2.add(100);编译时期报错list2.add("hello");list2.add("world");list2.add("java");for (String str : list2) {System.out.println(str.length());}}
}

前面曾提过, 集合中是可以存放任意对象的, 只要把对象储存集合后, 那么这是他们都会被提升成Object类型. 当我们在取出每一个对象, 并进行相应的操作, 必须==采用类型转换==.

看一段代码:

import java.util.Iterator;public class GenericTest {public static void main(String[] args) {Collection coll = new ArrayList();coll.add("捣乱黄");coll.add("捣乱绿");coll.add(5);//由于集合并没有限定,所以任何类型都可以给其中存放Iterator it = coll.iterator();while (it.hasNext()){//需要打印每个字符串的长度, 就要把迭代出来的对象转成String类型String str =(String) it.next();System.out.println(str.length());}}
}//3
//3
//Exception in thread "main" java.lang.ClassCastException: class java.lang.Integer cannot be cast to class java.lang.String (java.lang.Integer and java.lang.String are in module java.base of loader 'bootstrap')
//  at drafts.drafts3.GenericTest.main(GenericTest.java:16)

程序在运行时抛出了java.lang.ClassCastException.类型转换异常

为什么会出现此异常呢?

由于集合中什么类型都可以储存, 导致取出时强制转换, 引发运行时ClassCastException.

Collection虽然可以储存各种对象, 但实际上, 通常Collection只储存同一类型对象, 因此, 在JDK1.5后, 新增了泛型(Generic)语法

使得在设计API时可以指定类或方法支持泛型, 这样我们使用API的时候也变得更为简洁, 并得到了==编译时运行检查==.

  • 泛型 : 可以在类或方法中预支的使用未知的类型,

tips : 一般在创建对象时, 将未知的类型确定具体的类型, 当没有指定泛型时, 默认类型为Object类型.

2. 泛型的好处

  1. 将运行时期的ClassCastException, 转移到了编译时期变成编译失败
  2. 省去了向下转型的操作(只是操作层面省去了, 下详)

看下面一段代码: 体现了省去向下转型

package drafts.drafts4;import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;public class GenericTest2 {public static void main(String[] args) {Collection <String> list = new ArrayList<>();list.add("捣乱黄");list.add("捣乱绿");//list.add(666); 这时, 不是String类型的元素就会编译报错Iterator<String> it = list.iterator();while (it.hasNext()){String str = it.next();//当使用Iterator<String>控制元素类型后, 就不需要强转了, //获取到的元素就是String类型System.out.println(str.length());}}
}

tips: 泛型时数据类型的一部分, 我们将类名与泛型合并一起看做数据类型

泛型擦除: 泛型也是语法糖, 本质还是要做向下转型.

Java中的泛型都是伪泛型, 泛型只在源代码阶段有效, 一旦编译, 泛型就会消失, 俗称泛型参数

package drafts.drafts10;
import java.util.ArrayList;
/*泛型擦除, 在用xjad反编译.class文件后发现Java中的泛型都是伪泛型, 泛型只在源代码阶段有效, 一旦编译, 泛型就会消失, 俗称泛型擦除*/
@SuppressWarnings("all")
public class GenericTest2 {public static void main(String[] args) {ArrayList<String> list2 = new ArrayList<>();//list2.add(100);编译时期报错list2.add("hello");list2.add("world");list2.add("java");for (String str : list2) {System.out.println(str.length());}       //编译之后泛型就没了, 本质其实还是向下转型}
}

3. 泛型的定义与使用

​ 泛型, 是一种未知的不确定的数据类型. 用来灵活的将数据类型应用到不同的类, 方法, 接口中. 将数据类型作为参数进行传递.

​ 如果定义类的时候, 在类名后面加上, 此时就表示定义了一个未知的, 不确定的数据类型T , 这个T就是一个泛型, T可以用任何字母代替, 但一般用T (type)

这个位置的数据类型T会在我们使用这个类的时候确定下来

### 3.1 含有泛型的类( 泛型类 )

定义格式 :

修饰符 class 类名 <代表泛型的变量> {    }例如, API中的ArrayList集合class ArrayList<E>{public boolean add (E e) {}public E get (int index) {}...
}

在类中定义的泛型在整个类中都可以使用

泛型在定义的时候不具体, 使用的时候才具体, 在使用的时候确定泛型的具体数据类型

在创建对象的时候确定泛型 :

例如, ArrayList<String> list = new ArrayList<String> ();

此时, 变量E的值就是String类型. 那么我们的类型就可以理解为 :

class ArrayList<String>{public boolean add (String e) {}public String get (int index) {}...
}

3.2 含有泛型的方法

​ 如果想要延后泛型类型的确认时间, 那么可以使用泛型方法. 如果将泛型定义在方法上, 那么该方法就是一个泛型方法

​ 在方法上定义的泛型, 需要调用方法的时候才能够确定这个泛型是什么类型

定义格式 :

修饰符 <代表泛型的变量> 返回值类型 方法名 (参数列表) { ... }

例如 :

public class MyGenericMethod {public <E> void show <E e> {System.out.println(mvp.getClass());}public <E> E show2 (E e) {return e;}
}

调用方法时, 确定泛型的类型

public class GenericMethodDemo {public static void main (String[] args){//创建对象MyGenericMethod mm = new MyGenericMethod();mm.show("aaa");    //class java.lang.Stringmm.show(1234);     //class java.lang.Integermm.show(12.211);   //class java.lang.Double}
}

定义方法, 接收什么参数, 就返回什么结果

: 表示在方法上定义了一个不确定的数据类型E

后面两个E: 使用泛型当做参数和返回值的数据类型

在方法上定义的泛型, 可以在整个方法中使用

在方法上定义的泛型, 需要调用这个方法的时候才能确定这个泛型表示的是什么类型.

public <E> E getSame(E e) {return e ;
}

小结 :

如果在类上面定义泛型, 那么类就是泛型类, 在类上面定义的泛型, 可以在整个类中使用, 类上面定义的泛型需要使用整个类的时候才能确定泛型的类型

如果在方法上面定义泛型, 那么这个方法就是泛型方法, 在方法上面定义的泛型, 可以在整个方法中使用, 方法上面定义的泛型需要使用该方法的时候才能确定泛型的类型

3.3 含有泛型的接口

如果在定义接口的时候在接口名后面加上尖括号, 那么这个接口就是一个泛型接口, 在接口中定义的泛型, 在整个接口中都可以使用.

定义格式 :

修饰符 interface 接口名<代表泛型的变量> {...}

例如 :

public interface MyInterface <T> {//表示定义了一个不确定的数据类型Tpublic abstract void add (E e);public abstract void E getE();
}

使用格式 :

3.3.1 定义类的时候确定泛型的类型

例如

public class MyImp1 implements MyGenericInterface<String> {@Overridepublic void add(String e) {// 省略...}@Overridepublic String getE() {return null;}
}

此时, 泛型E 的值就是String类型

3.3.2 直到创建对象时, 才确定泛型的类型

例如

public class MyImp2<E> implements MyGenericInterface<E> {@Overridepublic void add(E e) {// 省略...}@Overridepublic E getE() {return null;}
}

确定泛型 :

/*
* 使用
*/
public class GenericInterface {public static void main(String[] args) {MyImp2<String> my = new MyImp2<String>();            my.add("aa");}
}

泛型接口的使用:

3.4 泛型通配符

泛型之间是没有继承关系的, 比如ArrayList并不是ArrayList的父类
如果想要让泛型可以匹配任何类型的数据, 那么可以使用泛型通配符.
我们用?表示泛型通配符.
==注意 :== 泛型通配符要使用在参数位置==被动匹配==, 不能主动使用.
3.4.1 泛型通配符的使用
import java.util.ArrayList; /* 泛型之间是没有继承关系的。比如ArrayList<Object>并不是ArrayList<String>的父类。 如果想要让泛型可以匹配任何类型的数据,那么可以使用泛型通配符。 ? 表示泛型通配符,可以匹配任何类型的泛型。 注意: 泛型通配符要使用在参数位置被动匹配, 不能主动使用。 */ public class Demo01Generic { public static void main(String[] args) { //创建集合,用来保存字符串 ArrayList<String> strList = new ArrayList<>(); //添加元素 strList.add("Hello"); strList.add("World"); strList.add("Java"); //调用printArrayList方法,遍历集合 printArrayList(strList); //创建集合,保存Integer ArrayList<Integer> intList = new ArrayList<>(); //调用printArrayList,遍历 printArrayList(intList); //创建集合,使用?当做泛型类型 //ArrayList<?> list = new ArrayList<>(); //list.add(); } /* 定义一个方法,用来遍历存储任何类型数据的集合。 参数: ArrayList<Object> */ public static void printArrayList(ArrayList<?> list) { //?表示泛型通配符,可以匹配任何类型的泛型。 //对参数list集合进行遍历 for (Object obj : list) { System.out.println(obj); } } }
3.4.2 泛型限定
如果想要对?泛型通配符的使用范围进行限制,那么可以使用泛型限定(上限,下限)
<? extends A>:泛型类型要么是A类,要么是A类的子类, 孙子类...。 上限。 ​ <? super A>: 泛型类型要么是A类,要么是A类的父类, 爷爷类 直到Object类。 下限。
​ 泛型主要用于代码的重构.
示例:
import java.util.ArrayList; /* 如果想要对?泛型通配符的使用范围进行限制,那么可以使用泛型限定(上限,下限) <? extends A>:泛型类型要么是A类,要么是A类的子类。 上限。 <? super A>: 泛型类型要么是A类,要么是A类的父类。 下限。 泛型主要用于代码的重构. */ public class Demo02Generic { public static void main(String[] args) { //创建集合 ArrayList<Student> stuList = new ArrayList<>(); //添加元素 stuList.add(new Student("jack", 20)); stuList.add(new Student("rose", 12)); stuList.add(new Student("tony", 24)); //调用printArrayList方法 printArrayList(stuList); //创建集合 ArrayList<Person> personList = new ArrayList<>(); printArrayList(personList); //创建集合 ArrayList<Object> objList = new ArrayList<>(); //printArrayList(objList); 要求泛型要么是Person,要么是Person的子类,不能是Person的父类 //method(stuList); 泛型类型要么是Person,要么是Person的父类,不能是Person的子类 method(personList); method(objList); } /* 定义方法,使用集合当做参数。 */ public static void method(ArrayList<? super Person> list) { //泛型类型要么是Person,要么是Person的父类 } /* 要求:定义方法,遍历保存Person或者Person子类对象的集合。 */ public static void printArrayList(ArrayList<? extends Person> list) {//泛型的类型要么是Person,要么是Person的子类 for (Person p : list) { System.out.println(p); } } }

泛型方法的定义和使用_泛型( Generic )相关推荐

  1. DotNET:LINQ对泛型(Generic)操作和泛型方法及属性

    ylbtech-DotNET:泛型(Generic)和LINQ操作 1,遍历泛型集合 2,根据索引位置移除项(RemoveAt()) 3,查询一个人(Single()) 3.2,查询一个人(Singl ...

  2. 你真的了解泛型 Generic 嘛?

    泛型 Generic Programming[1] 通常指允许程序员在强类型程序设计语言中,编写代码时使用一些以后才指定的类型,在实例化时作为参数指明这些类型,即类型参数化 首先我们不是科班讨论学术, ...

  3. Java泛型(1)--集合使用泛型Generic、自定义泛型、泛型在继承上的体现、通配符的使用

    文章目录 泛型的概念 集合中使用泛型 自定义泛型结构 泛型在继承上的体现 通配符的使用 泛型的概念 集合容器类在设计阶段/声明阶段不能确定这个容器实际存的是什么类型的对象,所以在JDK1.5之前只能把 ...

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

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

  5. Java学习打卡第七天——[再谈Collection之Set,TreeSet,泛型Generic的简介和使用]

    说明:为了文章的简洁性和方便阅读在以后的打卡过程中,我会给出核心代码 Javaee之[Collection之Set] Javaee之[Collection之TreeSet] Javaee之[Colle ...

  6. java泛型(Generic)超详细

    目录 1.为什么要有泛型(Generic)? 2.泛型的设计背景 2.1那么为什么要有泛型呢,直接Object不是也可以存储数据吗? 3.在集合中使用泛型 4.自定义泛型结构 4.1自定义泛型结构:泛 ...

  7. 定义和使用含有泛型的接口

    含有泛型的接口 定义格式: 修饰符 interface接口名<代表泛型的变量> { } 例如, public interface MyGenericInterface<E>{p ...

  8. 定义和使用含有泛型的类

    泛型的定义与使用 我们在集合中会大量使用到泛型,这里来完整地学习泛型知识. 泛型,用来灵活地将数据类型应用到不同的类.方法.接口当中.将数据类型作为参数进行传递. 定义和使用含有泛型的类 定义格式: ...

  9. 获取list泛型_泛型

    泛型 什么是泛型?为什么使用泛型? 泛型的出现意味着编写的代码可以被不同类型的对象所重用,提升了代码的重用性.泛型的本质是参数化类型,即将所需操作的数据类型设置为一个参数. 举个实际中的栗子:我们需要 ...

最新文章

  1. 如何查看linux版本
  2. XP与Windows 7(Win7)等操作系统Ghost备份
  3. 数据字典怎么写_求职数据分析,项目经验该怎么写
  4. lunixs 退出mysql_MySQL的基本操作
  5. 用简单的代码测一测你是否真的了解:Asp.Net中的事件和委托的实现
  6. 两个工作流:什么时候选择BizTalk,什么时候选择WWF?微软人士给了一个简单的判断原则...
  7. 苹果Mac智能照片编辑软件:​​​​Movavi Picverse
  8. 最新手机号码、电话号码正则表达式
  9. 想做个磁力链搜索引擎 1
  10. c语言输入abc求平均值,怎样用C语言编写一个求平均数的程序?要求如下.刚学C语言,...
  11. c语言循环语句试讲教案,C语言For循环试讲教案(7页)-原创力文档
  12. USB-IF发布针对盲文点字显示器的HID标准
  13. 使用 Keras 进行面部表情识别
  14. mac 爱普生打印机驱动_爱普生l201打印机驱动下载Mac版-爱普生L201驱动Mac版下载 V8.7.5-PC6苹果网...
  15. Platform机制
  16. 常用的 Docker 命令
  17. java虚数复数计算_真实的虚数,不仅不是没用,而且还很实在
  18. 大学生阅读小说网页设计模板代码 小说书籍网页作业成品 学校书籍网页制作模板 学生简单书籍阅读网站设计成品
  19. bvp4c求边值问题matlab,例子10.6-3_bvp4c求解边值问题
  20. 【javaweb:eljstl】通过模拟用户登录,使网页登录测试部分变成“用户”和“退出”

热门文章

  1. android之inflater用法
  2. C++指针和数组的区别(不能混用的情况)
  3. Python中operator模块的操作
  4. php发送get、post请求获取内容的几种方法
  5. 减少图片HTTP 请求的方案
  6. 就业模拟试题_Net
  7. SUN JAVA面试笔试题
  8. go调用ethereum_Go语言爱好者周刊:第 76 期 — 新年计划做了吗?
  9. spring怎么设置定时任务为每天凌晨2点执行和每小时执行一次?(亲测)
  10. CATALINA_BASE和CATALINA_HOME,多实例tomcat与多版本tomcat运行