一,泛型机制介绍及为何要使用泛型

泛型机制是在Java SE5.0中增加的,使用泛型机制编写的程序代码要比那些杂乱地使用object变量,然后再进行强制转换的代码具有更好的安全性和可读性。泛型对于集合类尤其有效,例如,ArrayList就是一个无处不在的集合类。

集合可以存储任何类型的对象,但是存储一个对象到集合后,集合会“忘记”这个对象的类型,当该对象从集合中取出时,这个对象的编译类型就变成object类型。那么在取出元素时,如果进行强制类型转换就很容易抛出异常。

泛型,可以用来灵活地将数据类型应用到不同的类、方法、接口当中。将数据类型作为参数进行传递 。

1.1例子:集合中不使用泛型

package cn.xaomifeng1010;import java.util.ArrayList;
import java.util.List;public class Teee {public static void main(String[] args) {List list = new ArrayList();list.add(225);list.add(250);list.add(520);//1.没有使用泛型,任何Object及其子类的对象都可以添加进来list.add(new String("AA"));for(int i = 0;i < list.size();i++){//2.强转为int型时,可能报ClassCastException的异常int score = (Integer)list.get(i);System.out.println(score);}}}

运行后,报错

分析:上面的例子中,向List集合中存入了4个元素,分别是3个int类型和一个字符串类型。在取出这些元素时,都将他们强制转换成了Integer类型,由于String类型不能转换为Integer类型,因此在运行时抛出类转换异常,为了解决这个问题,Java中引用了“参数化类型”(parameterized type)这个概念,即泛型,它可以限定方法操作的类型,在定义集合类时,使用“<参数化类型>“的方法指定该类中方法操作的类型

1.2例子:在集合中使用泛型

package cn.xaomifeng1010;import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;public class GenericType {public static void main(String[] args) {List<Integer> list = new ArrayList<Integer>();list.add(225);list.add(250);list.add(520);
//          list.add("AA");//         for(int i = 0;i < list.size();i++){
//              int score = list.get(i);
//              System.out.println(score);
//          }Iterator<Integer> it = list.iterator();while(it.hasNext()){System.out.println(it.next());}}}

运行后结果

例子二:集合中使用泛型

package cn.xaomifeng1010;import java.util.HashMap;
import java.util.Map;
import java.util.Set;public class GenericTypeDemo2 {public static void main(String[] args) {Map<String,Integer> map = new HashMap<>();map.put("AA", 78);map.put("BB", 87);map.put("DD", 98);Set<Map.Entry<String,Integer>> set = map.entrySet();for(Map.Entry<String,Integer> o : set){System.out.println(o.getKey() + "--->" + o.getValue());}}}

运行结果

使用泛型之后,限定了集合存储元素的类型,该写后的程序,往集合中添加元素时只能添加制定类型的元素,例如 ArrayList<Integer>(),限定只能添加int类型数据,如果添加string类型就会报错(非法参数),这样限定元素类型避免了程序运行时发生出错,避免了在程序中进行强制类型转换。

二、自定义泛型类:应用

自己在创建类和接口时也可以根据需要自定义创建泛型类或者泛型接口。

2.1 定义泛型类:

例如:

package cn.xaomifeng1010;import java.util.List;public class DAO<T> {public void add(T t){}public T get(int index){return null;}public List<T> getForList(int index){return null;}public void delete(int index){}}
/*继承泛型类或者泛型接口时,可以指定泛型的具体类型,本例子中指定了DAO泛型类型为Integer,也可以不指定类型* 继续使用T类型,T表示任意类型
*/class CustomerDAO extends DAO<Integer> {}

测试泛型类

package cn.xaomifeng1010;public class TestCustomerDAO {public static void main(String[] args) {CustomerDAO c = new CustomerDAO();c.add(556);c.get(0);}}

【注意点】
1.对象实例化时不指定泛型,默认为:Object。
2.泛型不同的引用不能相互赋值。
3.加入集合中的对象类型必须与指定的泛型类型一致。
4.静态方法中不能使用类的泛型。
5.如果泛型类是一个接口或抽象类,则不可创建泛型  
  类的对象。
6.不能在catch中使用泛型
7.从泛型类派生子类,泛型类型需具体化

2.2 定义泛型接口:

定义格式:

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

例如:

public interface MyGenericInterface<E>{public abstract void add(E e);public abstract E getE();
}

使用格式:

2.2.1 在由类实现接口时确定泛型类型:

例如:

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

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

2.2.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");}
}

三、泛型与继承的关系

A类是B类的子类,G是带泛型声明的类或接口。那么G<A>不是G<B>的子类!通常G<A>与G<B>没有什么联系。

四、通配符类型

4.1 无限定通配符

A类是B类的子类,G是带泛型声明的类或接口。则G<?> 是G<A>、G<B>的父类!
①以List<?>为例,能读取其中的数据。因为不管存储的是什么类型的元素,其一定是Object类的或其子类的。
①以List<?>为例,不可以向其中写入数据。因为没有指明可以存放到其中的元素的类型!唯一例外的是:null

具体例子说明:

泛型类型中只有一个通配符?,是使用的无限定通配符,例如Pair<?>。乍看起来,似乎和原始的Pair类型一样,实际上,有很大不同。类型Pair<?>有以下方法:

?getFirst();

void setFirst(?);

getFirst的返回值只能赋给一个Object。setFirst方法不能被调用,甚至不能用Object调用。Pair<?>和Pair本质的不同在于:可以用任意Object对象嗲用原始Pair类的setObject方法。

但是可以调用setFirst(null)。

为什么要使用这么脆弱的类型?它对于许多简单的操作非常有用。例如,下面这个方法将用来测试一个pair是否包含一个null引用,它不需要实际的类型。

public static boolean hasNulls<Pair<?> p){return p.getFirst()==null || p.getSecond()==null;}

通过将hasNulls转换成泛型方法,可以避免使用通配符类型:

public static <T> boolean hsaNulls(Pair<T> p)

但是带有通配符的版本可读性更高。

4.2 有限定的通配符(通配符的子类限定)
List<? extends A> :可以将List<A>的对象或List<B>的对象赋给List<? extends A>。其中B 是A的子类(A类的子类都可以作为List<? extends A>的元素类型)。

可以总结为泛型的上限:只能接收该类型及其子类

注意extends后边的A可以是类,也可以是接口,而且A如果是接口时,可以有多个接口限定,之间用“&”分割,例如:

4.3 通配符的超类型限定
  List<? super A>:可以将List<A>的对象或List<B>的对象赋给List<? super A>。其中B 是A的父类(只有A类的超类即父类可以作为List<? super A>的元素类型)

可以总结为泛型的下限:只能接收该类型及其父类型

五,含有泛型的方法

5.1 在泛型类中定义的含有泛型的方法:

public class DAO<T> {public void add(T t){}public T get(int index){System.out.println(index);return null;}public List<T> getForList(int index){System.out.println(index);return null;}public void delete(int index){}public T update(T t) {System.out.println(t);return t;}}

注意:因为在声明类时已经定义了<>泛型,所以方法中就不需要定义泛型(即方法的修饰符后边不需要加<T>了),方法中的返回类型是泛型,方法参数是可以为泛型,也可以为其他确定类型的。

测试:

package cn.xiaomifeng1010.test;public class DAOdemoTest {public static void main(String[] args) {DAO<String> dao=new DAO<String>();dao.getForList(5);dao.get(7);dao.update("xiaomifeng");}}

运行结果:

5.2 在普通类中定义含有泛型的方法:

定义格式:

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

例如:

package cn.xiaomifeng1010.test;public class MyGenericMethod {public <T> void show(T t) {System.out.println(t.getClass());}public <T> T show2(T t) {  return t;}}

注意:这里和上边不同,因为这里是普通类,没有定义过泛型,所以在方法的修饰符后边就有了尖括号里面定义的泛型(即<T>),后边跟返回类型void(无返回)和T(返回T类型)。

测试,在创建对象后,调用方法时给定具体类型:

package cn.xiaomifeng1010.test;public class GenericMethodDemo {public static void main(String[] args) {MyGenericMethod test2=new MyGenericMethod();test2.show("123");test2.show(123);test2.show(123.23);System.out.println(test2.show2("xiaomifeng1010"));}}

运行结果:

文中小部分内容引用自《Java核心技术卷一 第10版》作者:Cay S.Horstmann

Java基础----泛型相关推荐

  1. Java基础 --- 泛型 Generics

    Java基础 --- 泛型 Generics 为什么需要泛型 泛型 Bounds for Type Variable Java虚拟机如何处理泛型 --- 泛型擦除 Restrictions and L ...

  2. java基础-泛型举例详解

    泛型 泛型是JDK5.0增加的新特性,泛型的本质是参数化类型,即所操作的数据类型被指定为一个参数.这种类型参数可以在类.接口.和方法的创建中,分别被称为泛型类.泛型接口.泛型方法. 一.认识泛型 在没 ...

  3. java 基础 泛型

    泛型是什么? 泛型,即"参数化类型".一提到参数,最熟悉的就是定义方法时有形参,然后调用此方法时传递实参.那么参数化类型怎么理解呢?顾名思义,就是将类型由原来的具体的类型参数化,类 ...

  4. Java基础—泛型的使用(详细)

    文章目录 目录 零.概念 一.泛型的优点 1.1优点 1.2为什么要使用泛型 二.泛型使用与不使用的区别 1.泛型的没有使用会造成什么后果呢? 2.添加泛型的使用会发生什么效果呢? [一.二] 知识点 ...

  5. [Java基础]泛型基础

    可变参数的使用: 代码如下: package CanChangePack;import java.util.Arrays; import java.util.List;public class Arg ...

  6. 六、JAVA基础--泛型

    泛型方法:泛型方法可以放在普通类中,也可以定义在泛型类中. <T extends 具体类或者接口> T为绑定类型的子类型:T和绑定类型可以是类,也可以是接口. 可以有多个限定类型,用'&a ...

  7. java 获取泛型t的class_阿里巴巴都鼎力推荐的java基础之集合其他内容和泛型3

    第三节 泛型 3.1为什么需要泛型 没有采用泛型之前 1.不安全:添加元素是无检查 宽进 2.繁琐:获取元素时需要强制类型转换 严出 采用泛型之后 1.安全 严进 2.简单 宽出 3.2什么是泛型ge ...

  8. Java基础-我所理解的泛型

    Java基础-我所理解的泛型 引用 [java]泛型中,? extends T 与 ? super T 的区别.看法_winrh的博客-CSDN博客_泛型 extends 前言 Java基础系列,我所 ...

  9. Java编程基础 - 泛型

    Java编程基础 - 泛型 [导读] . 什么是泛型 一般传统而言,泛型允许程序员在强类型语言中编写代码时使用一些以后才指定的类型,在实例化时作为参数指明这些类型. 编程技术发展至今很多语言,尤其是强 ...

最新文章

  1. 你的厨房被水淹了!别担心,这只是3D深度估计做出的特效
  2. python库管理_多版本python控制以及python三方库管理
  3. 【数据挖掘】数据挖掘算法 组件化思想 ( 模型或模式结构 | 数据挖掘任务 | 评分函数 | 搜索和优化算法 | 数据管理策略 )
  4. [iOS]利用通知实现监听系统键盘
  5. 动态规划训练22 [Milking Time POJ - 3616 ]
  6. S3C2440 lds链接脚本解析
  7. spring视频教程下载
  8. 视频教程-Go语言区块链开发入门视频教程-区块链
  9. pycharm专业版使用
  10. 树莓派浏览器this site can‘t be reached
  11. ZOJ - 3939(日期规律)
  12. Matlab2017a中帮助文档无法设置为中文的一种解决办法
  13. 教你如何对产品做AB测试(abtest)
  14. 如何把很多照片拼成一张照片_怎样用手机将多张照片拼成一张组合图?
  15. 文章4:多功能智能跟随行李箱控制系统设计 | 本科毕业设计 - 【资料搜索技巧+参考资源整合】
  16. 【MySQL·水滴计划】第三话- SQL的基本概念
  17. 程序员如何提高自己的逻辑思维和技术水平
  18. Java基础之父类引用指向子类对象
  19. Lake Shore350型低温温度控制器
  20. 安装Tomcat服务器

热门文章

  1. 获取(可能)关联数组中的第一个键?
  2. Activiti(6.0)任务管理服务TaskaskService
  3. TTU智能配电终端_智能终端+正泰云平台,让配电网更“聪明”
  4. MTK之UART串口收发数据
  5. makefile中 = ,:=,+=有怎么区别?
  6. ❤️六万字《Spring框架从入门到精通》(建议收藏)❤️
  7. 指针01:指针的定义与使用
  8. JSP的基础语法和指令(源码刨析,建议收藏)
  9. Unity PointCloud开发:Mesh渲染点云
  10. JS判断手机浏览器是横屏or竖屏