本文参考《Java核心技术 II 高级特性》有关章节

一. 为什么要使用泛型程序设计

泛型程序设计意味着编写的代码可以被很多不同类型的对象所重用。例如,我们不希望为聚集String和File对象分别设计不同的类。实际上根本不需要那么做,因为一个ArrayList类可以聚集任何类型的对象。这是一个泛型程序设计的实例。

在Java SE5.0之前,Java的泛型程序设计是用继承实现的,ArrayList类只负责维护一个Object引用的数组,看以下的代码:

public class ArrayList {public Object get(int i){return i;}public void add(Object o){ }private Object[] elementData;
}

实例化一个以上的ArrayList类对象:

ArrayList files = new ArrayList();
String filename = (String)m.get(0);  //获取一个值时必须强制类型转换
//files.add(new File("..."));  //由于这里没有错误检查,可以向数组列表中添加任何类的对象 

对于以上代码中的调用,编译和运行都不会出错。然而在其他地方,如果将get的结果强制类型转换为String类型,就会产生一个错误。

而现在泛型提供了一个更好的解决方案:类型参数(type parameters).ArrayList类有一个类型参数用来指示元素的类型:

ArrayList<String> files = new ArrayList<String>();

这使得代码具有更好的可读性。人们一看就知道这个数组列表中包含的是String类型对象。

      而编译器也可以很好的利用这个信息。当调用get的时候,不需要进行强制类型转换,编译器就知道返回值类型为String,而不是Object:

String filename = files.get(0);

编译器还将知道ArrayList<String>中的add方法有一个类型为String 的参数。这将比使用Object 类型的参数更加安全一点。现在编译器可以进行检查,避免插入错误类型的对象。比如:

//files.add(new File("...")); //这里的这行代码是无法通过编译的。

出现编译错误比类在运行时出现强制类型转换的异常要好的多。类型参数的魅力在于:使得程序具有更好的可读性和安全性。

二. 简单泛型类的定义

1. 简单泛型类的定义

一个泛型类(generic class)就是具有一个或者多个类型变量的类。 看下面的简单的泛型类Pair例子:

public class Pair<T>
{public Pair() { first = null; second = null; }public Pair(T first, T second) { this.first = first;  this.second = second; }public T getFirst() { return first; }public T getSecond() { return second; }public void setFirst(T newValue) { first = newValue; }public void setSecond(T newValue) { second = newValue; }private T first;private T second;
}

Pair类引入一个类型变量T,用尖括号(<>)括起来,并放在类名的后面。泛型类可以有多个类型变量。例如,可以定义Pair类,其中第一个域和第二个域使用不同的类型:

public class Pair<T,U>{...}

类定义中的类型变量指定方法的返回类型以及域和局部变量的类型,例如:

private T first;

注意:类型变量使用大写形式,而且比较短。在Java类库中使用变量E表示集合元素类型,K表示关键字类型,V表示值的类型,T表示任意类型。

2. 简单泛型类的实例化

用具体的类型替换类型参数就可以实例化泛型类型,比如:

Pair<String> x = ..

使用泛型类中的构造方法和成员方法是一定要注意类型参数的一致性,比如:

new Pair<T>(T a);
new Pair<String>(String a);  //若a的类型和T或者具体的String不一致时需要强制类型转换

3. 例子(泛型返回类型方法)

下面的代码列举了使用一个在普通类ArrayAlg中返回类型为泛型的方法minmax,用其来获取字符串数组words中的字符串字典排序。

Pair<T>泛型类:

public class Pair<T>
{public Pair() { first = null; second = null; }public Pair(T first, T second) { this.first = first;  this.second = second; }public T getFirst() { return first; }public T getSecond() { return second; }public void setFirst(T newValue) { first = newValue; }public void setSecond(T newValue) { second = newValue; }private T first;private T second;
}

PairTest1普通类:

public class PairTest1
{public static void main(String[] args){String[] words = { "Mary", "had", "a", "little", "lamb" };Pair<String> mm = ArrayAlg.minmax(words);      //这里mm的类型必须设置为Pair<String>,而不可以为Pair<T>System.out.println("min = " + mm.getFirst());System.out.println("max = " + mm.getSecond());}
}class ArrayAlg
{public static Pair<String> minmax(String[] a){if (a == null || a.length == 0) return null;String min = a[0];String max = a[0];for (int i = 1; i < a.length; i++){if (min.compareTo(a[i]) > 0) min = a[i];if (max.compareTo(a[i]) < 0) max = a[i];}return new Pair<String>(min, max);}
}

三. 泛型方法

1. 泛型方法的定义

上面已经介绍了如何定义一个泛型类。实际上,还可以定义一个带有类型参数的简单方法。看下面的模板:

public static <T> T getMiddle(T[] b) {return b[b.length/2];
}

这个方法是用在普通类中定义的,而不是用在泛型类中定义。但是,这是一个泛型方法,这一点可以从尖括号和类型变量中看出来。

需要注意的是,类型变量放在修饰符(这里是public static)的后面,返回类型的前面。当然泛型方法可以定义在普通类中,也可以定义在泛型类中。

2. 泛型方法的调用

当调用一个泛型方法时,在方法名前面的方括号中放入具体类型:

String[] names = { "John", "Q.", "public" };
String middle = ArrayAlg.<String>getMiddle(names);

      在这种情况下,方法调用中可以省略掉<String>类型参数。编译器有足够的信息来判断出多调用的方法。它用的names的类型(即String[ ]类型)与泛型类型T[ ]进行匹配,并且判断出T一定是String。也就是说以下对于泛型方法的调用的代码也是对的:

String middle = ArrayAlg.getMiddle(names);

3. 泛型方法例子

下面的代码列举了一个在普通类ArrayAlg中泛型方法getMiddle()的使用,其返回一个字符串数组的中间字符串。

Pair<T>泛型类

public class Pair<T>
{  //以下可看作是构造方法   public Pair() { first = null; second = null; }  public Pair(T middle){ this.middle = middle;} //以下可以看作是泛型类的成员方法   public T getMiddleOne(){return middle;}//以下两个可以看作是成员变量     private T middle;  public T length;   //length要用public或者默认访问修饰符
}

含有泛型方法getMiddle()的PairTest1普通类:

(第一种)

public class PairTest1
{public static void main(String[] args){String[] names = { "John", "Q.", "public" };Pair<String> middle = ArrayAlg.<String>getMiddle(names);  //如前所述Pair<String> middle = ArrayAlg.getMiddle(names);也可以。         System.out.println("mid = " + middle.getMiddleOne());       }
}
class ArrayAlg
{public static <T> Pair<String> getMiddle(T[] b)  //这里的泛型方法返回类型为Pair<String>{return new Pair<String>((String)b[b.length / 2]);  //b[b.length / 2]是T[]类型,所以要强制类型转换。}
}

或者

(第二种)

public class PairTest1
{public static void main(String[] args){String[] names = { "John", "Q.", "public" };Pair<String> middle = ArrayAlg.<String>getMiddle(names);  //如前所述Pair<String> middle = ArrayAlg.getMiddle(names);也可以。System.out.println("mid = " + middle.getMiddleOne());        }
}
class ArrayAlg
{public static <T> Pair<T> getMiddle(T[] b)  //这里的泛型方法返回类型为Pair<String>{return new Pair<T>(b[b.length / 2]);  //b[b.length / 2]是T[]类型,所以无需强制类型转换。}
}

泛型类、泛型方法的使用与理解相关推荐

  1. java泛型程序设计——定义简单泛型类+泛型方法

    [0]README 0.1) 本文描述+源代码均 转自 core java volume 1, 旨在理解 java泛型程序设计 的 定义泛型类+泛型方法的知识: [1]一个泛型类: 就是具有一个或多个 ...

  2. 【Flutter】Dart 泛型 ( 泛型类 | 泛型方法 | 特定类型约束的泛型 )

    文章目录 一.Dart 泛型类与泛型方法 二.Dart 泛型中的特定类型约束 三.Dart 自带泛型 四.完整代码示例 五. 相关资源 一.Dart 泛型类与泛型方法 泛型作用 : 为 类 , 接口 ...

  3. 【Java 泛型】泛型简介 ( 泛型类 | 泛型方法 | 静态方法的泛型 | 泛型类与泛型方法完整示例 )

    文章目录 一.泛型简介 二.泛型类 三.泛型方法 四.静态方法的泛型 五.泛型类与泛型方法完整示例 一.泛型简介 泛型 可以 简单理解为 参数化类型 , 主要作用在 类 , 方法 , 接口 上 ; j ...

  4. Java泛型(泛型类,泛型方法,静态方法泛型,泛型类与泛型方法例子)

    泛型 泛型简介 泛型可以理解为参数化类型,主要作用在类,方法和接口上. Java泛型 与 C++ 模板 : Java 中的泛型 , 是仿照 C++ 中的模板开发的 , 目的是让开发者可以写出通用,灵活 ...

  5. 鸟欲高飞先振翅,人求上进先读书 [泛型 泛型类 泛型方法 泛型接口 泛型通配符详解]

    文章目录 5. 泛型 5.1 泛型概述[理解] 5.2 为什么会引入泛型? 5.3 泛型的好处 5.4 泛型的定义格式 5.5 泛型类[应用] 5.6 泛型方法 5.7 泛型接口[应用] 5.8类型通 ...

  6. 今天我才明白了泛型,泛型类 泛型方法

    写程序一年多了.才懂得泛型真正的意思是.以前以为Ilist<>这样就是泛型. 今天豁然开朗.list其实是集合而泛型的真正是在后面那个尖括号里面. 转载于:https://blog.51c ...

  7. 【Java 泛型】泛型用法 ( 泛型类用法 | 泛型方法用法 | 泛型通配符 ? | 泛型安全检查 )

    文章目录 一.泛型类用法 二.泛型方法用法 三.泛型通配符 <?> 四.泛型安全检查 五.完整代码示例 1.泛型类 / 方法 2.main 函数 一.泛型类用法 泛型类用法 : 使用时先声 ...

  8. Java-Java5.0泛型解读

    概述 泛型类 泛型方法 泛型接口 边界符 通配符 PECS原则 类型擦除 概述 Java 泛型(generics)是 JDK 5 中引入的一个新特性, 泛型提供了编译时类型安全检测机制,该机制允许程序 ...

  9. JAVA泛型编程笔记

    1介绍 Java泛型编程是JDK1.5版本后引入的.泛型让编程人员能够使用类型抽象,通常用于集合里面. 下面是一个不用泛型例子: 1 List myIntList=new LinkedList(); ...

最新文章

  1. AI进军摇滚圈,老炮:这是啥?
  2. 自居电路(升压电路)
  3. java executorser 停止_Java使用ExecutorService来停止线程服务
  4. Vue 里的$如何理解
  5. idea java cpu100_intellij idea cpu占用率太大太满 运行速度太慢 使了五个解决方法最终成功...
  6. Linux平台上搭建apache+tomcat负载均衡集群
  7. 前端学习(616):变量的定义
  8. linux操作系统权限详解,Linux权限详解
  9. spring boot 三种入参
  10. 思杰新年动作片 | 超融合+公有云桌面虚拟化大战 VMware+AWS
  11. java knn kd树_KD树实现KNN
  12. Caterpillar CAT SIS卡特彼勒最新零件目录系统+维修信息
  13. 部分双机热备软件详细介绍-行云管家
  14. Cylinder Candy(zoj 3866 旋转体体积和表面积)
  15. 以影像技术为“桨“,荣耀如何讲好高端“新故事”?
  16. UHF超高频RFID纸质电子标签与树莓派通信
  17. android 仿快递步骤_Android实现仿美团、顺丰快递数据加载效果
  18. 神经网络的类型分类和结构理解
  19. C语言获取程序崩溃信号,打印调用栈backtrace、backtrace_symbols、addr2line
  20. win10直接打开服务器文档,win10如何打开数据库服务器

热门文章

  1. CANOE入门:CAPL语言(1)
  2. ChatGPT自动写了个AI办公office word插件,低配copilot,程序员看了焦虑。
  3. 微信小程序 本地存储及调用
  4. Java创建线程(Lambda表达式创建线程)
  5. linux堆内存管理
  6. 鼠标使用板载内存和使用计算机上,【罗技G700s无线鼠标使用总结】功能|配置|模式|灵敏度_摘要频道_什么值得买...
  7. 程序员后端学习路线大体了解
  8. 面试官100%会问的接口测试的知识
  9. ubuntu 麦克风录音_如何在Ubuntu中测试麦克风
  10. 工作心得之接口数据同步