转载出处:http://www.weixueyuan.net/view/6321.html 
我们知道,使用变量之前要定义,定义一个变量时必须要指明它的数据类型,什么样的数据类型赋给什么样的值。

假如我们现在要定义一个类来表示坐标,要求坐标的数据类型可以是整数、小数和字符串,例如: 
x = 10、y = 10 
x = 12.88、y = 129.65 
x = “东京180度”、y = “北纬210度”

针对不同的数据类型,除了借助方法重载,还可以借助自动装箱和向上转型。我们知道,基本数据类型可以自动装箱,被转换成对应的包装类;Object 是所有类的祖先类,任何一个类的实例都可以向上转型为 Object 类型,例如: 
int –> Integer –> Object 
double –>Double –> Object 
String –> Object

这样,只需要定义一个方法,就可以接收所有类型的数据。请看下面的代码:

public class Demo {
public static void main(String[] args){
Point p = new Point(); p.setX(10); // int -> Integer -> Object
p.setY(20);
int x = (Integer)p.getX(); // 必须向下转型
int y = (Integer)p.getY();
System.out.println("This point is:" + x + ", " + y); p.setX(25.4); // double -> Integer -> Object
p.setY("东京180度");
double m = (Double)p.getX(); // 必须向下转型
double n = (Double)p.getY(); // 运行期间抛出异常
System.out.println("This point is:" + m + ", " + n);
}
} class Point{
Object x = 0;
Object y = 0; public Object getX() {
return x;
}
public void setX(Object x) {
this.x = x;
}
public Object getY() {
return y;
}
public void setY(Object y) {
this.y = y;
}
}

上面的代码中,生成坐标时不会有任何问题,但是取出坐标时,要向下转型,在 Java多态对象的类型转换 一文中我们讲到,向下转型存在着风险,而且编译期间不容易发现,只有在运行期间才会抛出异常,所以要尽量避免使用向下转型。运行上面的代码,第12行会抛出 java.lang.ClassCastException 异常。

那么,有没有更好的办法,既可以不使用重载(有重复代码),又能把风险降到最低呢?

有,可以使用泛型类(Java Class),它可以接受任意类型的数据。所谓“泛型”,就是“宽泛的数据类型”,任意的数据类型。

更改上面的代码,使用泛型类:

public class Demo {
public static void main(String[] args){
// 实例化泛型类
Point<Integer, Integer> p1 = new Point<Integer, Integer>();
p1.setX(10);
p1.setY(20);
int x = p1.getX();
int y = p1.getY();
System.out.println("This point is:" + x + ", " + y); Point<Double, String> p2 = new Point<Double, String>();
p2.setX(25.4);
p2.setY("东京180度");
double m = p2.getX();
String n = p2.getY();
System.out.println("This point is:" + m + ", " + n);
}
} // 定义泛型类
class Point<T1, T2>{
T1 x;
T2 y;
public T1 getX() {
return x;
}
public void setX(T1 x) {
this.x = x;
}
public T2 getY() {
return y;
}
public void setY(T2 y) {
this.y = y;
}
}

运行结果: 
This point is:10, 20 
This point is:25.4, 东京180度

与普通类的定义相比,上面的代码在类名后面多出了 <T1, T2>,T1, T2 是自定义的标识符,也是参数,用来传递数据的类型,而不是数据的值,我们称之为类型参数。在泛型中,不但数据的值可以通过参数传递,数据的类型也可以通过参数传递。T1, T2 只是数据类型的占位符,运行时会被替换为真正的数据类型。

传值参数(我们通常所说的参数)由小括号包围,如 (int x, double y),类型参数(泛型参数)由尖括号包围,多个参数由逗号分隔,如<T> 或 <T, E>

类型参数需要在类名后面给出。一旦给出了类型参数,就可以在类中使用了。类型参数必须是一个合法的标识符,习惯上使用单个大写字母,通常情况下,K 表示键,V 表示值,E 表示异常或错误,T 表示一般意义上的数据类型。

泛型类在实例化时必须指出具体的类型,也就是向类型参数传值,格式为: 
className variable<dataType1, dataType2> = new className<dataType1, dataType2>()
也可以省略等号右边的数据类型,但是会产生警告,即: 
className variable<dataType1, dataType2> = new className();

因为在使用泛型类时指明了数据类型,赋给其他类型的值会抛出异常,既不需要向下转型,也没有潜在的风险,比本文一开始介绍的自动装箱和向上转型要更加实用。

注意: 
泛型是 Java 1.5 的新增特性,它以C++模板为参照,本质是参数化类型(Parameterized Type)的应用。 
类型参数只能用来表示引用类型,不能用来表示基本类型,如 int、double、char 等。但是传递基本类型不会报错,因为它们会自动装箱成对应的包装类。 
泛型方法

除了定义泛型类,还可以定义泛型方法,例如,定义一个打印坐标的泛型方法:

public class Demo {
public static void main(String[] args){
// 实例化泛型类
Point<Integer, Integer> p1 = new Point<Integer, Integer>();
p1.setX(10);
p1.setY(20);
p1.printPoint(p1.getX(), p1.getY()); Point<Double, String> p2 = new Point<Double, String>();
p2.setX(25.4);
p2.setY("东京180度");
p2.printPoint(p2.getX(), p2.getY());
}
} // 定义泛型类
class Point<T1, T2>{
T1 x;
T2 y;
public T1 getX() {
return x;
}
public void setX(T1 x) {
this.x = x;
}
public T2 getY() {
return y;
}
public void setY(T2 y) {
this.y = y;
} // 定义泛型方法
public <T1, T2> void printPoint(T1 x, T2 y){
T1 m = x;
T2 n = y;
System.out.println("This point is:" + m + ", " + n);
}
}

运行结果: 
This point is:10, 20 
This point is:25.4, 东京180度

上面的代码中定义了一个泛型方法 printPoint(),既有普通参数,也有类型参数,类型参数需要放在修饰符后面、返回值类型前面。一旦定义了类型参数,就可以在参数列表、方法体和返回值类型中使用了。

与使用泛型类不同,使用泛型方法时不必指明参数类型,编译器会根据传递的参数自动查找出具体的类型。泛型方法除了定义不同,调用就像普通方法一样。

注意:泛型方法与泛型类没有必然的联系,泛型方法有自己的类型参数,在普通类中也可以定义泛型方法。泛型方法 printPoint() 中的类型参数 T1, T2 与泛型类 Point 中的 T1, T2 没有必然的联系,也可以使用其他的标识符代替:

public static <V1, V2> void printPoint(V1 x, V2 y){
V1 m = x;
V2 n = y;
System.out.println("This point is:" + m + ", " + n);
}

泛型接口

在Java中也可以定义泛型接口,这里不再赘述,仅仅给出示例代码:

public class Demo {
public static void main(String arsg[]) {
Info<String> obj = new InfoImp<String>("www.weixueyuan.net");
System.out.println("Length Of String: " + obj.getVar().length());
}
} //定义泛型接口
interface Info<T> {
public T getVar();
} //实现接口
class InfoImp<T> implements Info<T> {
private T var; // 定义泛型构造方法
public InfoImp(T var) {
this.setVar(var);
} public void setVar(T var) {
this.var = var;
} public T getVar() {
return this.var;
}
}

运行结果: 
Length Of String: 18 
类型擦除

如果在使用泛型时没有指明数据类型,那么就会擦除泛型类型,请看下面的代码:

public class Demo {
public static void main(String[] args){
Point p = new Point(); // 类型擦除
p.setX(10);
p.setY(20.8);
int x = (Integer)p.getX(); // 向下转型
double y = (Double)p.getY();
System.out.println("This point is:" + x + ", " + y);
}
} class Point<T1, T2>{
T1 x;
T2 y;
public T1 getX() {
return x;
}
public void setX(T1 x) {
this.x = x;
}
public T2 getY() {
return y;
}
public void setY(T2 y) {
this.y = y;
}
}

运行结果: 
This point is:10, 20.8

因为在使用泛型时没有指明数据类型,为了不出现错误,编译器会将所有数据向上转型为 Object,所以在取出坐标使用时要向下转型,这与本文一开始不使用泛型没什么两样。 
限制泛型的可用类型

在上面的代码中,类型参数可以接受任意的数据类型,只要它是被定义过的。但是,很多时候我们只需要一部分数据类型就够了,用户传递其他数据类型可能会引起错误。例如,编写一个泛型函数用于返回不同类型数组(Integer 数组、Double 数组、Character 数组等)中的最大值:

public <T> T getMax(T array[]){
T max = null;
for(T element : array){
max = element.doubleValue() > max.doubleValue() ? element : max;
}
return max;
}

上面的代码会报错,doubleValue() 是 Number 类的方法,不是所有的类都有该方法,所以我们要限制类型参数 T,让它只能接受 Number 及其子类(Integer、Double、Character 等)。

通过 extends 关键字可以限制泛型的类型,改进上面的代码:

public <T extends Number> T getMax(T array[]){
T max = null;
for(T element : array){
max = element.doubleValue() > max.doubleValue() ? element : max;
}
return max;
}

<T extends Number> 表示 T 只接受 Number 及其子类,传入其他类型的数据会报错。这里的限定使用关键字 extends,后面可以是类也可以是接口。但这里的 extends 已经不是继承的含义了,应该理解为 T 是继承自 Number 类的类型,或者 T 是实现了 XX 接口的类型。

注意:一般的应用开发中泛型使用较少,多用在框架或者库的设计中,这里不再深入讲解,主要让大家对泛型有所认识,为后面的教程做铺垫。

Java泛型详解,通俗易懂只需5分钟的更多相关文章

  1. java 泛型详解-绝对是对泛型方法讲解最详细的,没有之一

    对java的泛型特性的了解仅限于表面的浅浅一层,直到在学习设计模式时发现有不了解的用法,才想起详细的记录一下. 本文参考java 泛型详解.Java中的泛型方法. java泛型详解 1. 概述 泛型在 ...

  2. 【转】java 泛型详解

    java 泛型详解 对java的泛型特性的了解仅限于表面的浅浅一层,直到在学习设计模式时发现有不了解的用法,才想起详细的记录一下. 本文参考java 泛型详解.Java中的泛型方法. java泛型详解 ...

  3. 【转载】Java泛型详解

    [转载]http://www.importnew.com/24029.html 对java的泛型特性的了解仅限于表面的浅浅一层,直到在学习设计模式时发现有不了解的用法,才想起详细的记录一下. 本文参考 ...

  4. Java泛型详解(转)

    文章转自  importNew:Java 泛型详解 引言 泛型是Java中一个非常重要的知识点,在Java集合类框架中泛型被广泛应用.本文我们将从零开始来看一下Java泛型的设计,将会涉及到通配符处理 ...

  5. java 泛型详解(普通泛型、 通配符、 泛型接口)

    java 泛型详解(普通泛型. 通配符. 泛型接口) JDK1.5 令我们期待很久,可是当他发布的时候却更换版本号为5.0.这说明Java已经有大幅度的变化.本文将讲解JDK5.0支持的新功能---- ...

  6. java基础(十二 )-----Java泛型详解

    本文对java的泛型的概念和使用做了详尽的介绍. 概述 泛型在java中有很重要的地位,在面向对象编程及各种设计模式中有非常广泛的应用. 什么是泛型?为什么要使用泛型? 泛型,即“参数化类型”.一提到 ...

  7. Java基础11:Java泛型详解

    本文对java的泛型的概念和使用做了详尽的介绍. 本文参考https://blog.csdn.net/s10461/article/details/53941091 具体代码在我的GitHub中可以找 ...

  8. java 泛型详解-绝对是对泛型方法讲解

    Reference:  http://blog.csdn.net/s10461/article/details/53941091 1. 概述 泛型在java中有很重要的地位,在面向对象编程及各种设计模 ...

  9. Java泛型详解,史上最全图文详解!

    泛型在java中有很重要的地位,无论是开源框架还是JDK源码都能看到它. 毫不夸张的说,泛型是通用设计上必不可少的元素,所以真正理解与正确使用泛型,是一门必修课. 一:泛型本质 Java 泛型(gen ...

  10. 笔记-java泛型详解

    首先,先说明一下,java泛型文章的出处:http://www.cnblogs.com/lzq198754/p/5780426.html 作为学习笔记保存. 1.为什么需要泛型 泛型在Java中有很重 ...

随机推荐

  1. Lun4R-CyBRICSCTF wp

    WEB Hunt (Web, Baby, 50 pts) 打断点,然后就一个一个被抓住了... 接着F12就出现了.(这个flag是白色的,藏在下面....)... RE Baby Rev 题目给了个 ...

  2. rsync 的用法

    rsync官方网站: https://www.samba.org/ftp/rsync/rsync.html rsync是可以实现增量备份的工具.配合任务计划,rsync能实现定时或间隔同步,配合ino ...

  3. ken桑带你读源码 之scrapy pipelines\images.py

    大家先看看 http://www.cnblogs.com/attitudeY/p/7078559.html 下面我做一些补充   最新版本1.1 已经支持 下载路径保存到  item   48行    ...

  4. PHP stripos() 函数

    实例 查找 "php" 在字符串中第一次出现的位置: <?php高佣联盟 www.cgewang.comecho stripos("I love php, I lo ...

  5. PHP hebrevc() 函数

    实例 反向显示希伯来字符,并把新行(\n)转换为 <br>: <?php高佣联盟 www.cgewang.comecho hebrevc("á çùåï äúùñâ\ná ...

  6. ajax模拟表单提交,后台使用npoi实现导入操作 方式一

    页面代码: <form id="form1" enctype="multipart/form-data"> <div style=" ...

  7. luogu P3217 [HNOI2011]数矩形

    LINK:数矩形 题意:给出n个点 求出一个最大的矩形. 矩形可以使斜着的.(不会告诉你样例我算了几年 这道题的一个潜规则 矩形面积都是整数 我也不知道为啥一定是整数 姑且是题目输出的要求吧. 所以用 ...

  8. zabbix监控配置一般流程

    目录 zabbix监控配置流程 1. 配置客户端 2. 配置监控 2.1 创建主机组 2.2 添加主机并加入主机组 2.3 添加监控项 2.3.1 模板的方式(不用添加触发器) 2.3.2 手动添加的 ...

  9. python数据处理PDF高清电子书

    点击获取提取码:jzgv 内容简介 本书采用基于项目的方法,介绍用Python完成数据获取.数据清洗.数据探索.数据呈现.数据规模化和自动化的过程.主要内容包括:Python基础知识,如何从CSV.E ...

  10. 树形DP 学习笔记(树形DP、树的直径、树的重心)

    前言:寒假讲过树形DP,这次再复习一下. -------------- 基本的树形DP 实现形式 树形DP的主要实现形式是$dfs$.这是因为树的特殊结构决定的——只有确定了儿子,才能决定父亲.划分阶 ...