使用泛型机制编写的程序代码要比那些杂乱地使用Object变量,然后再进行强制类型转换的代码具有更好的安全性和可读性。
泛型程序设计意味着编写的代码可以被很多不同类型的对象所重用。
一个泛型类就是具有一个或多个类型变量的类。
如下面的Pair例子,就是一个泛型类
package ch13genic;
public class Pair<T> {
private T first;
private T second;
public Pair(){
first = null;
second = null;
}
public T getFirst() {
return first;
}
public void setFirst(T first) {
this.first = first;
}
public T getSecond() {
return second;
}
public void setSecond(T second) {
this.second = second;
}
public Pair(T first, T second) {
this.first = first;
this.second = second;
}
}
该类引人了类型变量T,用尖括号<>扩起,放在类名的后面,泛型类可以有多个类型变量,例如public class Pair<T,U>{....},
用具体的类型替换类型变量就可以实例化泛型类型:如Pair<String>,泛型类可以看做普通类的工厂。
package ch13genic;
public class PairTest1
{
public static void main(String[] args)
{
String[] words = { "Mary", "had", "a", "little", "lamb" };
Pair<String> mm = ArrayAlg.minmax(words);
System.out.println("min = " + mm.getFirst());
System.out.println("max = " + mm.getSecond());
String midStr = ArrayAlg.<String>getMiddle(words); //调用泛型方法,也可以省略<String>,因为编译器根据words匹配T[] a,判断出T一定是String。
System.out.println(midStr);
// int[] a = {1,23,45,56,3};
// int aMid = ArrayAlg.getMiddle(a); 编译出错,为什么?猜测:因为T是一个类型变量,代表的是一个类,而int只是基本类型
// Integer[] a ={1,23,45,56,3};
// int aMid = ArrayAlg.getMiddle(a);
// System.out.println(aMid);
}
}
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);
}
public static <T> T getMiddle(T[] a){
//示意:带有类型参数的方法。由于这个类不是在泛型类中定义的,要用<T>引人类型变量,它放在修饰符和返回值之间
return a[a.length/2];
}
}
类型变量的限定
有时类或方法需要对类型变量加以约束。下面是一个典型的例子
class ArrayAlg{
public static <T> T min(T[] a) {
if (a == null || a.length == 0)
return null;
T min = a[0];
for (int i = 0; i < a.length; i++) {
if (min.compareTo(a[i]) < 0)
min = a[i];
}
return min;
}
}
这里有一个问题,变量min的类型为T,意味着它可以是任何一个类的对象。怎么才能确信T所属的类有compareTo方法呢?
解决这个问题的答案是将T限制为实现了Comparable接口的类,如
public static <T extends Comparable> T min(T[] a){
}
实际上,Comparable本身就是一个泛型接口:public interface Comparable<T>,唯一的方法:compareTo(T o) 如果该对象小于、等于或大于指定对象,则分别返回负整数、零或正整数。
可能有些奇怪,为什么使用关键字extends而不是implements?比较,Comparable是一个接口啊,下面的符号:
<T extends BoundingType>
表示T应该是绑定类型的子类型,T和绑定类型可以是类,也可以是接口。
一个类型变量可以有多个限定,例如
T extends Comparable & Serializable
限定类型用 & 分隔,这是因为用逗号分隔类型变量
package ch13genic;
import java.util.*;
public class PairTest2
{
public static void main(String[] args)
{
GregorianCalendar[] birthdays =
{
new GregorianCalendar(1906, Calendar.DECEMBER, 9), // G. Hopper
new GregorianCalendar(1815, Calendar.DECEMBER, 10), // A. Lovelace
new GregorianCalendar(1903, Calendar.DECEMBER, 3), // J. von Neumann
new GregorianCalendar(1910, Calendar.JUNE, 22), // K. Zuse
};
Pair<GregorianCalendar> mm = ArrayAlg.minmax(birthdays);
System.out.println("min = " + mm.getFirst().getTime());
System.out.println("max = " + mm.getSecond().getTime());
}
}
class ArrayAlg
{
/**
Gets the minimum and maximum of an array of objects of type T.
@param a an array of objects of type T
@return a pair with the min and max value, or null if a is
null or empty
*/
public static <T extends Comparable> Pair<T> minmax(T[] a)
{
if (a == null || a.length == 0) return null;
T min = a[0];
T 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<T>(min, max);
}
}
泛型的约束和限制:
不能用类型参数替换基本类型,因此没有Pair<double>,只有Pair<Double>.虚拟机没有泛型类型对象,所有对象都是
普通对象。所有的类型查询只产生原始类型,如List而非List<String>等。getClass总是返回原始类型。
if(a instanceof Pair<String>)等价if(a instanceof Pair)
Pair<String> p = new Pair("first", "second");
Pair<Integer> p1 = new Pair();
System.out.println(p.getClass().getName());// ch13genic.Pair
System.out.println(p1.getClass().getName()); // ch13genic.Pair
List<String> l1 = new ArrayList<String>();
List<Integer> l2 = new ArrayList<Integer>();
System.out.println(l1.getClass().getName());// java.util.ArrayList
System.out.println(l2.getClass().getName()); // java.util.ArrayList
泛型类不能扩展Throwable。如public class Problem<T> extends Exception {
。。。
} //error The generic class Problem<T> may not subclass java.lang.Throwable
不能在catch子句中使用类型变量。如下面的方法将不能编译:
try{
//do work
}catch(T e){ //error:Cannot use the type parameter T in a catch block
// logger.info("");
}
}
但是,在异常声明中可以使用类型变量。下面这个方法是合法的:
public static <T extends Throwable> void doWork(T t) throws T{//ok
try{
//do work
}catch(Throwable e){ //error:Cannot use the type parameter T in a catch block
t.initCause(e);
throw t;
}
}
不能申明参数化类型的数组,如:
Pair<String>[] table = new Pair<String>(10); //error
如果需要收集参数化类型对象,直接使用ArrayList:ArrayList<Pair<String>>最安全且有效。
不能实例化泛型类型,如:
public Pair(T first, T second) { //error
this.first = new T();
this.second = new T();
}
不能建立一个泛型数组,如:
T[] t = new T[20]; //error
不能在静态域或方法中引用类型变量,如:
public class Singleton<T> {
private static T singleInstance; //error:Cannot make a static reference to the non-static type T
public static T getSingleInstance(){//error
if(singleInstance==null){
// construct new instance of T
}
return singleInstance;
}
}
一个类和一个子类,Pair<Employee>与Pair<Manager>,前者是后者的子类吗?不是。无论S、T有何关系,Pair<S>和Pair<T>没有什么联系。
分享到:
相关推荐
下面我们将详细探讨Java泛型接口的相关知识点。 1. **泛型接口的定义** 泛型接口的定义方式与普通接口类似,只是在接口名之后添加了尖括号`<T>`,其中`T`是一个类型参数,代表某种未知的数据类型。例如: ```java...
下面我们将深入探讨Java泛型方法的概念、语法以及使用示例。 **一、泛型方法概念** 泛型方法是一种具有类型参数的方法,这些类型参数可以在方法声明时指定,并在方法体内部使用。与类的泛型类似,它们提供了编译时...
在Java编程语言中,泛型(Generics)是一种强大的特性,它允许我们在编写代码时指定容器(如集合)可以存储的数据类型。这提高了代码的安全性和效率...通过学习和理解这些示例,你可以更好地掌握Java泛型类的类型识别。
Java泛型的用法及T.class的获取过程解析 Java泛型是Java编程语言中的一种重要特性,它允许开发者在编写代码时指定类型参数,从而提高代码的灵活性和可读性。本文将详细介绍Java泛型的用法 及T.class的获取过程解析...
Java 泛型使用详细分析 Java 泛型是 Java 语言中的一种类型系统特性,允许开发者在编译期检查类型安全,以避免在运行时出现类型相关的错误。在本文中,我们将详细介绍 Java 泛型的使用方法和实现原理。 一、泛型的...
#### 一、什么是Java泛型? Java泛型(Generics)是一种在编译时确保类型安全的机制,它允许程序员编写类型安全的通用类或方法,而无需进行显式的类型转换。在Java 1.5引入泛型之前,集合类(如`ArrayList`)只能...
Java泛型是Java编程语言中的一个关键特性,它在2004年随着JDK 5.0的发布被引入。泛型的主要目的是提供类型安全,帮助程序员在编译时发现可能的类型错误,同时也提供了更好的代码重用。在这个"java泛型Demo"中,我们...
Java泛型是Java语言中用于处理类型安全的一种机制,它允许在编译期间提供类型检查,并在运行时消除了类型转换。Java泛型深入的内容涵盖泛型的基本概念、泛型类、接口、方法以及泛型的使用限制和高级特性。 首先,...
了解这些概念后,我们可以看到`GenericClass.java`文件可能包含了关于如何创建和使用继承泛型类的实际代码示例。而`Java.jpg`可能是用于辅助解释的图像,比如类结构图或代码截图。在实际学习过程中,结合代码和图像...
### Java泛型的使用详细讲解 #### 一、引言 在Java开发中,泛型是一种重要的语言特性,它能够帮助开发者在不增加代码量的情况下处理多种数据类型,同时还能保持代码的清晰度和可读性。本文将详细介绍Java泛型的...
Java泛型是Java编程语言中的一个...在“java泛型的高级用法demo”中,你可以期待更深入的示例,如限制类型参数、创建多级泛型、使用泛型接口等复杂应用场景。实践这些示例将有助于进一步理解并熟练掌握Java泛型的精髓。
### JVM如何理解Java泛型类 #### 一、引言 在Java中,泛型是一种强大的功能,它允许程序员编写灵活且类型安全的代码。然而,对于Java虚拟机(JVM)来说,它实际上并不理解泛型的概念。所有的泛型信息在编译阶段就被...
### 泛型示例解析 #### 示例一:泛型类 ```java class Point<T> { private T var; public T getVar() { return var; } public void setVar(T var) { this.var = var; } } ``` 这里定义了一个泛型类`...
Java泛型是Java编程语言中的一个关键特性,它在2004年随着JDK 5.0的发布被引入,极大地增强了类型安全性和代码可读性。泛型允许我们在编写代码时指定容器(如集合)可以存储的数据类型,从而在编译阶段就能捕获类型...
Java泛型是Java语言的一个重要特性,它允许在类、接口和方法中声明类型参数,从而提高了代码的复用性和安全性。这个特性自Java 5引入以来,极大地改善了Java的类型系统,降低了类型转换异常的风险。 1. **使用泛型...
Java泛型是Java编程语言中的一个重要特性,它在2004年随着Java SE 5.0的发布而引入。这个特性允许程序员在定义类、接口和方法时声明类型参数,从而增强了代码的类型安全性和重用性。通过使用泛型,我们可以编写更加...
Java泛型与容器详细笔记涉及到Java编程语言中的两个重要概念:泛型(Generics)和容器(Containers)。容器主要包括Java集合框架中的各类集合类,如List、Set、Map等,它们用于存储和操作数据。泛型则提供了一种类型...