根据《Java编程思想 (第4版)》中的描述,泛型出现的动机在于:

有许多原因促成了泛型的出现,而最引人注意的一个原因,就是为了创建容器类。

泛型类

容器类应该算得上最具重用性的类库之一。先来看一个没有泛型的情况下的容器类如何定义:

public class Container {
private String key;
private String value; public Container(String k, String v) {
key = k;
value = v;
} public String getKey() {
return key;
} public void setKey(String key) {
this.key = key;
} public String getValue() {
return value;
} public void setValue(String value) {
this.value = value;
}
}

Container类保存了一对key-value键值对,但是类型是定死的,也就说如果我想要创建一个键值对是String-Integer类型的,当前这个Container是做不到的,必须再自定义。那么这明显重用性就非常低。

当然,我可以用Object来代替String,并且在Java SE5之前,我们也只能这么做,由于Object是所有类型的基类,所以可以直接转型。但是这样灵活性还是不够,因为还是指定类型了,只不过这次指定的类型层级更高而已,有没有可能不指定类型?有没有可能在运行时才知道具体的类型是什么?

所以,就出现了泛型。

public class Container<K, V> {
private K key;
private V value; public Container(K k, V v) {
key = k;
value = v;
} public K getKey() {
return key;
} public void setKey(K key) {
this.key = key;
} public V getValue() {
return value;
} public void setValue(V value) {
this.value = value;
}
}

在编译期,是无法知道KV具体是什么类型,只有在运行时才会真正根据类型来构造和分配内存。可以看一下现在Container类对于不同类型的支持情况:

public class Main {

    public static void main(String[] args) {
Container<String, String> c1 = new Container<String, String>("name", "findingsea");
Container<String, Integer> c2 = new Container<String, Integer>("age", 24);
Container<Double, Double> c3 = new Container<Double, Double>(1.1, 2.2);
System.out.println(c1.getKey() + " : " + c1.getValue());
System.out.println(c2.getKey() + " : " + c2.getValue());
System.out.println(c3.getKey() + " : " + c3.getValue());
}
}

输出:

name : findingsea
age : 24
1.1 : 2.2

泛型接口

在泛型接口中,生成器是一个很好的理解,看如下的生成器接口定义:

public interface Generator<T> {
public T next();
}

然后定义一个生成器类来实现这个接口:

public class FruitGenerator implements Generator<String> {

    private String[] fruits = new String[]{"Apple", "Banana", "Pear"};

    @Override
public String next() {
Random rand = new Random();
return fruits[rand.nextInt(3)];
}
}

调用:

public class Main {

    public static void main(String[] args) {
FruitGenerator generator = new FruitGenerator();
System.out.println(generator.next());
System.out.println(generator.next());
System.out.println(generator.next());
System.out.println(generator.next());
}
}

输出:

Banana
Banana
Pear
Banana

泛型方法

一个基本的原则是:无论何时,只要你能做到,你就应该尽量使用泛型方法。也就是说,如果使用泛型方法可以取代将整个类泛化,那么应该有限采用泛型方法。下面来看一个简单的泛型方法的定义:

public class Main {

    public static <T> void out(T t) {
System.out.println(t);
} public static void main(String[] args) {
out("findingsea");
out(123);
out(11.11);
out(true);
}
}

可以看到方法的参数彻底泛化了,这个过程涉及到编译器的类型推导和自动打包,也就说原来需要我们自己对类型进行的判断和处理,现在编译器帮我们做了。这样在定义方法的时候不必考虑以后到底需要处理哪些类型的参数,大大增加了编程的灵活性。

再看一个泛型方法和可变参数的例子:

public class Main {

    public static <T> void out(T... args) {
for (T t : args) {
System.out.println(t);
}
} public static void main(String[] args) {
out("findingsea", 123, 11.11, true);
}
}

输出和前一段代码相同,可以看到泛型可以和可变参数非常完美的结合。

以上,泛型的第一部分的结束。

Java泛型:泛型类、泛型接口和泛型方法的更多相关文章

  1. java 泛型 -- 泛型类,泛型接口,泛型方法

    泛型T泛型的许多最佳例子都来自集合框架,因为泛型让您在保存在集合中的元素上指定类型约束.在定义泛型类或声明泛型类的变量时,使用尖括号来指定形式类型参数.形式类型参数与实际类型参数之间的关系类似于形式方 ...

  2. Java 泛型-泛型类、泛型方法、泛型接口、通配符、上下限

    泛型: 一种程序设计语言的新特性,于Java而言,在JDK 1.5开始引入.泛型就是在设计程序的时候定义一些可变部分,在具体使用的时候再给可变部分指定具体的类型.使用泛型比使用Object变量再进行强 ...

  3. Java泛型(泛型接口、泛型类、泛型方法)

    转载 转载出处:https://www.cnblogs.com/JokerShi/p/8117556.html 泛型接口: 定义一个泛型接口: 通过类去实现这个泛型接口的时候指定泛型T的具体类型. 指 ...

  4. java泛型-泛型类,泛型接口,常用形式

    泛型简单使用: package com.etc; import java.util.ArrayList; import java.util.List; /* 泛型就相当于<>一个标签,泛化 ...

  5. Java泛型学习笔记 - (三)泛型方法

    泛型方法其实和泛型类差不多, 就是把泛型定义在方法上, 格式大概就是: public <类型参数> 返回类型 方法名(泛型类型 变量名) {...}泛型方法又分为动态方法和静态方法,:1. ...

  6. 利用Java泛型实现简单的泛型方法

    问题:编写一个泛型方法add(),当传入不同数字类型的值时,能够进行加法运算,(如可以传入int.long.float.double类型,但要对传入的值做一定的限定,如必须是数字). 解决:利用泛型编 ...

  7. 全面总结Java泛型

    本文对Java泛型进行了全面的总结.文章内容包括普通泛型.通配符.受限泛型.泛型接口.泛型方法.返回泛型类型实例等等. 虽然Scala创始人Martin Odersky说当年正是因为Java泛型的丑陋 ...

  8. java 泛型详解(普通泛型、 通配符、 泛型接口,泛型数组,泛型方法,泛型嵌套)

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

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

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

  10. java泛型应用实例 - 自定义泛型类,方法

    近 短时间需要使用泛型,就研究了下,发现网上的问关于泛型的文章都是讲原理的, 很少有提到那里用泛型比较合适, 本文就泛型类和泛型方法的使用给出两 个典型应用场景. 例如一个toString的泛型方法, ...

随机推荐

  1. 委托[delegate]_C#

    委托(delegate): 委托声明定义了一种类型,它用一组特定的参数以及返回类型来封装方法.对于静态方法,委托对象封装要调用的方法.对于实例方法,委托对象同时封装一个实例和该实例上的一个方法.如果您 ...

  2. 【转载】应读者强烈要求给出《超容易的Linux系统管理入门书》一书的主要知识点

    刚开始了一篇连载,收到广大Linux爱好者的反馈,非常欣慰.大家对Linux学习感到很迷茫,不知道学哪些内容,如何学习? <超容易的Linux系统管理入门书>一书是腾讯Linux专家在腾讯 ...

  3. 膜拜 2014-2 (献给L之三)

    文/安然 深深的夜静静的想你细细的品味满满的甜蜜爱,心灵的对话让我流泪战栗谢谢你给我这么弥足珍贵的体会不能一生相随又有什么关系你一直都在我的爱就永不停息此生足以——献给心底的爱

  4. (UVALive 7261)Xiongnu's Land 二分

    题目链接:https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_ ...

  5. 关于RadAsm中GetEnvironmentStrings的BUG。

    今天在asm中不通过msvcrt.inc调用c库. 所以.第一时间就在vc的lib中拷贝了libc.lib问价.加入工程后. 声明.调用如下: 然后.链接报错. libc.lib(crt0.obj) ...

  6. Percona-Server-5.5.33-31.1安装

    一.下载 http://www.percona.com/downloads/Percona-Server-5.5/ Percona-Server-5.5.33-31.1 选择 binary 选择lin ...

  7. 【转】DataGridView显示行号

    ref:http://blog.csdn.net/xieyufei/article/details/9769631 方法一: 网上最常见的做法是用DataGridView的RowPostPaint事件 ...

  8. Node.js Cannot find Module xxx 的问题

    不知道为什么第一天Node.js干的挺顺利的,回公司后就干的一点都不顺利,主要原因还是公司的网络的问题,使用的受限制的代理,不能直接使用NPM从远程下载模块,唉. node.js的模块加载顺序首先是从 ...

  9. 前端工程模块化——以一个php项目为例

    实现一个页面功能总是需要 JavaScript.CSS 和 Template 三种语言相互组织,所以我们真正需要的是一种可以将 JavaScript.CSS 和 Template 同时都考虑进去的模块 ...

  10. 【转】STL中mem_fun和mem_fun_ref的用法及区别

    原文:http://www.cppblog.com/mysileng/archive/2012/12/25/196615.html 引子: 怎么对容器中的所有对象都进行同一个操作?我们可能首先想到的是 ...