目录

1.为什么要有泛型(Generic)?

2.泛型的设计背景

2.1那么为什么要有泛型呢,直接Object不是也可以存储数据吗?

3.在集合中使用泛型

4.自定义泛型结构

4.1自定义泛型结构:泛型类、泛型接口

4.2自定义泛型结构:泛型方法

5.泛型在继承上的体现

6.通配符的使用

6.1使用类型通配符:?

6.2有限制的通配符:


1.为什么要有泛型(Generic)?

泛型:标签

举几个例子:

1 中药店,每个抽屉外面贴着标签

2.超市购物架上很多瓶子,每个瓶子装的是什么,有标签

3.垃圾箱分类,在垃圾箱上标明垃圾的分类形式。

实际上就是说,你具体要使用什么,根据标签提示,放进去,如果不对应是放不进去的。相当于加了一个限制的条件。这是在编译过程中所表现出来的,如果不对就会报错。

2.泛型的设计背景

集合容器类在设计阶段/声明阶段不能确定这个容器到底实际存的是什么类型的 对象,所以在JDK1.5之前只能把元素类型设计为Object,JDK1.5之后使用泛型来 解决。因为这个时候除了元素的类型不确定,其他的部分是确定的,例如关于 这个元素如何保存,如何管理等是确定的,因此此时把元素的类型设计成一个 参数,这个类型参数叫做泛型。Collection<E>,List<E>,ArrayList<E> 这个就 是类型参数,即泛型。

2.1那么为什么要有泛型呢,直接Object不是也可以存储数据吗?

1. 解决元素存储的安全性问题,好比商品、药品标签,不会弄错。

2. 解决获取数据元素时,需要类型强制转换的问题,好比不用每回拿商品、药 品都要辨别。

我们之前用的数组定义的类型只能是相同数据类型,就是单一的数据类型,集合(Object obj)类型,各种类型都能存入到里边,不够严格,引入泛型后表明是单一的数据类型。

举例说明一下:

在没有使用泛型之前重写compareto()方法需要: if (o instanceof Employee)判断是不是Employee数据类型。

@Overridepublic int compareTo(Object o) {if (o instanceof Employee){Employee e= (Employee) o;return this.name.compareTo(e.name);//从小到大}throw new RuntimeException("传入数据不一致");}

如果我们直接就知道这个数据类型相同指定泛型直接这样写:

使用泛型

@Overridepublic int compareTo(Employee o) {//不用判断数据类型,直接都是Employee类型的return this.name.compareTo(o.name);//从小到大}

3.在集合中使用泛型

泛型的使用
* 一.jdk5.0之后增加的特性
* 二.在集合中使用泛型
* 总结:
* 1.集合接口 或集合类 jdk5.0后都修改为带泛型的结构
* 2.在实例化集合类时,可以指明具体的泛型类型
* 3.指明完后,在集合类或接口中,凡是定义类和接口时,
* 内部结构使用到类的泛型的位置,都指定为实例化时的泛型类型
* 比如:add(E e)---->实例化后:add(Integer e) 看集合上边实例化指明的数据类型
*4.注意:我们泛型类型必须是类,不能是基本数据类型,需要用到包装类的位置,就拿包装类来进行替换
*5.如果实例化时,没有用泛型,默认类型为Object 的类型
* 三.如何自定义泛型类,泛型结构:泛型类,泛型接口,泛型方法
举例说明一下:

1.类型不安全性,我们有时候需要用某个具体的类型就容易出错。我也想到了可以用数组解决,但是数组的方法操作比较少,相对于集合用泛型解决了这个问题。

定义一个集合用来存放学生成绩,最终我们要的数据类型应该都是相同的,那么问题来了,在集合中我们可以存放各种数据类型即Object类型,我们在遍历时想要统一类型,进行强转,就出错。

@Testpublic void test1(){ArrayList list = new ArrayList();//存放学生成绩 存放一个别的数据类型list.add(78);list.add(88);list.add(98);list.add(100);//问题1:类型不安全,没有限制 都是Object 类型数据//list.add("aa");//不能转为int型,报异常 所以说不可以在list中不能添加别的数据类型的数据for (Object score:list){//向下强转时有可能出现ClassCastExceprionint stuscore= (Integer) score;System.out.println(stuscore);}}

2.解决类型不安全性,引入泛型之后在编译的时候直接爆红给出警告,添加不进去,就避免了各种类型鱼龙混杂的问题,也避免了要去来回的进行数据的强转问题:

//在集合中使用泛型//以ArrayList举例@Testpublic void test2(){ArrayList<Integer> list = new ArrayList<Integer>();//泛型不能使用基本的数据类型,只能使用包装类的形式//这就限制了数据类型list.add(78);list.add(88);list.add(98);list.add(100);//解决问题一:编译时进行类型检查,保证数据的安全//list.add("aa");//这时候就报异常了编译的时候报异常//遍历方式一for (Integer score:list){//避免了强转操作,强转操作容易出现问题。 其实还是用了泛型的优势int stuScore=score;System.out.println(stuScore);}//方式二 //定义结构的时候就使用了泛型//public interface Iterator<E>Iterator<Integer> iterator = list.iterator();while (iterator.hasNext()){Integer stuScore = iterator.next();System.out.println(stuScore);}}
//集合中使用泛型之前情况 HashMap()为例@Testpublic void test3(){//jdk新特性  后边这个new hashmap<>泛型可省略 默认推断//Map<String, Integer> map = new HashMap<String, Integer>();Map<String, Integer> map = new HashMap<>();map.put("Tom",89);map.put("meme",87);map.put("didi",69);map.put("Jack",100);
//        map.put(hhd,12);//有泛型报错 不满足形参的要求Set<Map.Entry<String,Integer>>entry=map.entrySet();// Set<E> Entry<K,V>嵌套一块Iterator<Map.Entry<String, Integer>> iterator = entry.iterator();while (iterator.hasNext()){Map.Entry<String, Integer> e = iterator.next();String key = e.getKey();Integer value = e.getValue();System.out.println(key+"-->"+value);}}

4.自定义泛型结构

1. 自定义泛型类

2. 自定义泛型接口

3. 自定义泛型方法

 如何自定义泛型类,泛型结构:泛型类,泛型接口,泛型方法
* 1.关于自定义泛型类 接口这两个基本是一会事,只是接口和类的区别
* 2.泛型要么用,要么别用 一般都要用
* 如果泛型结构是一个接口或抽象类 ,测不可以创建对象
* 测试

4.1自定义泛型结构:泛型类、泛型接口

1. 泛型类可能有多个参数,此时应将多个参数一起放在尖括号内。比如:<E1,E2,E3>

可行的

2. 泛型类的构造器如下:public GenericClass(){}。

而下面是错误的:public GenericClass<E>(){}

爆红

3. 实例化后,操作原来泛型位置的结构必须与指定的泛型类型一致。

4. 泛型不同的引用不能相互赋值。 尽管在编译时ArrayLis<String>t和ArrayList<Inetger>是两种类型,但是,在运行时只有 一个ArrayList会被加载到JVM中。

5. 泛型如果不指定,将被擦除,泛型对应的类型均按照Object处理,但不等价于Object。经验:泛型要使用一路都用。要不用,一路都不要用。

 @Testpublic void test1(){//如果定义了泛型,实例化时没有指明类的泛型,则认为次泛型类型为object类型的//如果定义类是泛型的,那么建议实例化时要指明类的泛型Order order = new Order();order.setOrderT(123);order.setOrderT("sdf");//建议带上泛型在实例化时指明泛型类型Order<String> order1 = new Order<String>("tom",1001,"aa");order1.setOrderT("tom:hello");}

6. 如果泛型结构是一个接口或抽象类,则不可创建泛型类的对象。

7. jdk1.7,泛型的简化操作:ArrayList <String>list = new ArrayList<>();

8. 泛型的指定中不能使用基本数据类型,如果要使用基本数据类型可以使用包装类替换。

//使用基本数据类型,必须使用包装类来替换,因为泛型也是一个类的对象

9. 在类/接口上声明的泛型,在本类或本接口中即代表某种类型,可以作为非静态 属性的类型、非静态方法的参数类型、非静态方法的返回值类型。但在静态方法中不能使用类的泛型。

原因://静态方法中不能使用类的泛型
//因为泛型时在创建对象实例化之前创建的
//而静态方法是在创建对象之前就已经执行了

10. 异常类不能是泛型的

异常类不能使用泛型:因为异常类 Exception这个API中没有使用泛型

11. 不能使用new E[]。但是可以:E[] elements = (E[])new Object[capacity]; 参考:ArrayList源码中声明:Object[] elementData,而非泛型参数类型数组。

12.父类有泛型,子类可以选择保留泛型也可以选择指定泛型类型:

1. 子类不保留父类的泛型:按需实现  没有类型 擦除  具体类型

2.子类保留父类的泛型:泛型子类  全部保留  部分保留

结论:子类必须是“富二代”,子类除了指定或保留父类的泛型,还可以增加自己的泛型

4.2自定义泛型结构:泛型方法

方法,也可以被泛型化,不管此时定义在其中的类是不是泛型类。在泛型方法中可以定义泛型参数,此时,参数的类型就是传入数据的类型。

 泛型方法的格式: [访问权限] 返回类型 方法名([泛型标识 参数名称]) 抛出的异常

//泛型方法 在方法中出现了泛型的结构,泛型的参数与类的泛型参数没有任何关系
//换句话说,泛型方法所属的类是不是泛型类都没有关系。
//认为这个类是E 而这个E是一个变量
//而在前边加个<E>这时候它知道了这是个变量,如果不在访问权限 前加<E>,系统默认是一个名字为E的一个类
//这个方法是泛型方法
//这个E是在调用的时候用的
//泛型方法可以声明为静态的,主要原因是泛型参数是在调用的时候确定的,并非在实例化才可以调用
 public static <E> List<E> copyFromArrayToList(E[] arr){ArrayList<E> list = new ArrayList<>();for (E e:arr){list.add(e);}return list;}

测试://泛型方法在调用时,指明泛型参数的类型

@Testpublic void test4(){Order<String > order=new Order<>();Integer[] arr=new Integer[]{1,2,3,3};//泛型方法在调用时,指明泛型参数的类型List<Integer> list = order.copyFromArrayToList(arr);System.out.println(list);}

结果:

5.泛型在继承上的体现

如果B是A的一个子类型(子类或者子接口),而G是具有泛型声明的 类或接口,G并不是G的子类型。

比如:String是Object的子类,但是List<String>并不是List<Object>的子类。

反证法:
假设 list1=list2,list1.add(123);导致list2中混入非string中的数据,这个泛型时不对的,编译不通过 不具备并列关系,

 /*1.泛型在继承方面的体现虽然类A是类B的父类,但是G<A> 与G<B>没有父子类关系,二者是并列的关系补充:类A是类B的父类 A<G> B<G> 他们之间是什么关系*/@Testpublic void test1(){Object obj=null;String str=null;obj=str;Object[] arr=null;String[] arr2=null;arr=arr2;//多态的 对象与对象之间的使用List<Object>list1=new ArrayList<Object>();List<String>list2=new ArrayList<String>();//此时的list1与list2不具有子分类关系。//编译不通过// list1=list2;/*反证法:假设list1=list2,list1.add(123);导致list2中混入非string中的数据,这个泛型时不对的,编译不通过 不具备并列关系*/}

6.通配符的使用

6.1使用类型通配符:?

比如:List <?>,Map<?,?>

List<?>是List<String>、List<Integer>等各种泛型List的父类。

2.读取List<?>的对象list中的元素时,永远是安全的,因为不管list的真实类型 是什么,它包含的都是Object。

3.写入list中的元素时,不行。因为我们不知道c的元素类型,我们不能向其中添加对象。

唯一的例外是null,它是所有类型的成员.

//写入的过程
//添加 对于list用了通配符之后就不可以加数据了
//限制添加数据,除了添加null之外。
//所有类类对象都是可以加null的

将任意元素加入到其中不是类型安全的:这样不又回到了之前,那还要泛型干什么!

Collection c = new ArrayList();

c.add(new Object()); // 编译时错误

因为我们不知道c的元素类型,我们不能向其中添加对象。add方法有类型参数E作为集 合的元素类型。我们传给add的任何参数都必须是一个未知类型的子类。因为我们不知 道那是什么类型,所以我们无法传任何东西进去。

唯一的例外的是null,它是所有类型的成员。

另一方面,我们可以调用get()方法并使用其返回值。返回值是一个未知的类型,但是我们知道,它总是一个Object。

 @Testpublic void test3(){List<Object> list1=null;List<String> list2=null;List<?> list=null;list=list1;list=list2;//表现为list<?>是父类//print(list);// print(list2);//ArrayList<String> list3 = new ArrayList<>();list3.add("ss");list3.add("bb");list3.add("cc");list3.add("dd");list=list3;//写入的过程//添加 对于list用了通配符之后就不可以加数据了//限制添加数据,除了添加null之外。//所有类类对象都是可以加null的list.add(null);//获取 允许读取数据,读取的数据类型是object的类型。以多态的方式进行读的Object o = list.get(0);System.out.println(o);}

使用通配符要注意以下几点:

6.2有限制的通配符:

3.有限制条件的统配符的使用

* ?extends A

* G<? ectends A> 可以作为G<A> 和G<B>的父类,其中B是A的子类

* ?super A

* G<? ectends A> 可以作为G<A> 和G<B>的父类,其中B是A的父类

代码中有详细注释:

@Testpublic void test4(){List<? extends Person>list1=null;//把extends看成小于等于 负无穷到person有上界List<? super Person> list2=null;//把super看成大于等于,有下届没有上界List<Student>list3=new ArrayList<Student>();List<Person>list4=new ArrayList<Person>();List<Object>list5=new ArrayList<Object>();list1=list3;list1=list4;//list1=list5;//list2=list3;list2=list4;list2=list5;//读数据list1=list4;Person person = list1.get(0);list1=list3;Person person1 = list1.get(0);list2=list4;Object object = list2.get(0);//写入数据//编译不通过// list1.add(new Student())//编译通过。list2.add(new Person());list2.add(new Student());}

java泛型(Generic)超详细相关推荐

  1. Java - 泛型 ( Generic )

    Java - 泛型 ( Generic ) > 泛型的特点 > 解决元素存储的安全性问题 > 解决获取数据元素时,需要类型强转的问题 > 不能在 static 方法中使用泛型, ...

  2. JAVA 正则表达式 (超详细,转)

    转 JAVA 正则表达式 (超详细,转) 2015年03月25日 10:27:57 阅读数:1514 在Sun的Java JDK 1.40版本中,Java自带了支持正则表达式的包,本文就抛砖引玉地介绍 ...

  3. 一文搞懂 Java 泛型,非常详细!

    作者: ZiWenXie http://www.ziwenxie.site/2017/03/01/java-generic/ 引言 泛型是Java中一个非常重要的知识点,在Java集合类框架中泛型被广 ...

  4. JAVA 正则表达式 (超详细)

    新网站上线 欢迎大家 网站交易中心 在这里你可以购买或者出售你的网站. 网站信息发布中心 在这里有各种交易信息的发布.同时提供 一些软件的免费使用(附有源码). 网站博客系统 这里你可以注册自己的博客 ...

  5. Java虚拟机(JVM)超详细面试题

    文章目录 一.Java内存区域 1.1 说一下 JVM 的主要组成部分及其作用? 1.2 说一下 JVM 运行时数据区 1.3 详细的介绍下程序计数器? 1.4 详细介绍下Java虚拟机栈? 1.5 ...

  6. JAVA 正则表达式 (超详细) .

    2019独角兽企业重金招聘Python工程师标准>>> 在Sun的Java JDK 1.40版本中,Java自带了支持正则表达式的包,本文就抛砖引玉地介绍了如何使用java.util ...

  7. Java正则表达式(超详细)

    学习Java的同学注意了!!!  学习过程中遇到什么问题或者想获取学习资源的话,欢迎加入Java学习交流群,群号码:183993990  我们一起学Java! 在Sun的Java JDK 1.40版本 ...

  8. Java异常(超详细!)

    1.什么是异常,java提供异常处理机制有什么用? 什么是异常:程序执行过程中的不正常情况. 异常的作用:增强程序的 健壮性. eg. public class ExceptionTest01 {pu ...

  9. Java——集合(超详细超级全)

    集合 Java 集合类可以用于存储数量不等的多个对象,还可用于保存具有映射关系的关联数组. 在这里主要讲一些我们平常很常用的一些接口和一些实现类. Java 集合可分为 Collection 和 Ma ...

最新文章

  1. 成为优秀程序员的方法就是抛开编程?
  2. 前端学习(3146):react-hello-react之getDenvied
  3. 计算机技术在机械设计中的应用,计算机技术在机械设计制造和自动化中的应用(原稿)...
  4. 第三章 Joomla!扩展开发:后端开发
  5. 每日一则----算法----二分查找法
  6. Cinder - 云硬盘加密
  7. 客户组网服务案列_信息报道丨云浮支撑服务中心2020年第五期
  8. oracle中的代码在那里写,oracle中如何编写树级代码-数据库专栏,ORACLE
  9. 电脑qq音乐显示无法代理服务器,电脑QQ音乐软件无法登录如何解决
  10. 【STM32H7教程】第39章 STM32H7的DMAMUX基础知识(重要)
  11. 蒟蒻数据观二叉树(基础篇)
  12. python去掉最高分和最低分怎么算平均分_去掉最高分和最低分算平均分并进行排名...
  13. 入手评测 暗影骑士龙和暗影骑士擎哪个更值得入手
  14. 关于三维数组的一些问题
  15. 新一代打包神器Walle(瓦力)使用小结
  16. 精选案例集 | 实现网安人才培养,保障网络强国战略—赛宁实训靶场
  17. 2013 province java c-2 组素数
  18. 京东夺宝岛抢拍插件(转)
  19. 计算机能不能升级固态硬盘,不算很老的计算机升级,换一块MLC的固态硬盘吧,新电脑回来了!...
  20. 英语每日阅读---2、越来越多人反对人工智能参战

热门文章

  1. 树莓派Pi OS Lite安装桌面
  2. 13条建议,睡个好觉吧
  3. thickbox 应用
  4. Java基础2——配置环境变量
  5. TOOLFK工具-在线摩斯电码翻译转换工具
  6. 最美的英文 - 第九篇 - love
  7. 计算机网络基础知识——网络层知识框架
  8. ubuntu 禁止/取消系统自动更新的方法
  9. oracle flashback 功能,开启oracle的flashback闪回功能
  10. Java学习之Path路径