`
mindfocus
  • 浏览: 17568 次
  • 性别: Icon_minigender_1
  • 来自: 福州
社区版块
存档分类
最新评论

泛型(Generics)

阅读更多
重温了一下泛型,心得记录如下。

1)什么是泛型?   
泛型(Generics)是相对于类型(Type)而言的,泛型是对类型的抽象。泛型最常见的应用是在集合或容器中,即在泛化的数据结构或算法中使用。泛型的命名约定一般是单个大写字母,并用一对尖括号<>括在其中。泛型的作用之一,是可以在编译时而不是运行时检查类型转换的错误,即消除类型转换,使得代码更清晰,更健壮。

效果之一:在空间上,通过泛型引入的类型检查机制可以精确地定位错误的位置,而无泛型时类型转换的错误可能远离代码中断运行的现场。
Debugging may be difficult, as the point in the code where the exception is thrown may be far removed from the point in the code where the error is located.
效果之二:在时间上,通过泛型引入的类型检查机制可以提前发现错误,并且其类型擦除(Type Erasure)机制可以自动地进行类型转换。
It's always better to catch bugs when compiling than when running.
  

2)泛型在类型与运算中的运用
泛型可用在类型(generic classes and generic interfaces),也可用在运算上(generic methods and generic constructors)。这里头涉及到一些概念:formal type parameter 形式化类型参数,actual type argument 实际类型参数,type variable类型变量, type value类型值,parameterized type 参数化类型。generic type declaration 泛型类型声明,type inference类型推断等。

public class Box<T> {

    private T t;          

    public void add(T t) {
        this.t = t;
    }

    public T get() {
        return t;
    }

    public <U> void inspect(U u){
        System.out.println("T: " + t.getClass().getName());
        System.out.println("U: " + u.getClass().getName());
    }

    public static void main(String[] args) {
        Box<Integer> integerBox = new Box<Integer>();
        integerBox.add(new Integer(10));
        integerBox.inspect("some text");
    }
}



3)泛型的边界
单个大写字母标识的具名泛型可以有上限,问号标识的未名(未知)的泛型可以有上限或下限。
Bounded type parameters limit the kinds of types that can be passed into a type parameter; they can specify an upper bound only. Wildcards represent unknown types, and they can specify an upper or lower bound.

关键字extends指定泛型的上限(upper bound),表示其类(class)扩展的限制(必须扩展该类)或接口(interface)实现的限制(必须实现该接口)的含义。如果要求该泛型同时满足扩展某类以及实现某接口,则需要&运算符号。<T extends SomeClass & SomeInterface>
extends is used in a general sense to mean either "extends" (as in classes) or "implements" (as in interfaces).

关键super指定泛型的下限(lower bound),表示其类(class)或接口(interface)必须为某类所继承(inheritance)或实现(implementation),即是该类的父类或父接口。如果要求该泛型同时满足为某类所或接口所扩展实现,则需要&运算符号。<T super SomeClass&SomeInterface>

一般的,当对输入参数类型有限制时,可以使用下限通配符(? super T);对返回参数类型有限制时,可以使用上限通配符(? extends T)。
In general, if you have an API that only uses a type parameter T as an argument, its uses should take advantage of lower bounded wildcards (? super T). Conversely, if the API only returns T, you'll give your clients more flexibility by using upper bounded wildcards (? extends T).


public class Box<T> {

    private T t;          

    public void add(T t) {
        this.t = t;
    }

    public T get() {
        return t;
    }

    public <U extends Number> void inspect(U u){
        System.out.println("T: " + t.getClass().getName());
        System.out.println("U: " + u.getClass().getName());
    }

    public static void main(String[] args) {
        Box<Integer> integerBox = new Box<Integer>();
        integerBox.add(new Integer(10));
        integerBox.inspect("some text"); // error: this is still String! 
    }
}


举例
Cage<? extends Animal> 上限通配符,必须是Animal的子类。
Cage<? super Animal> 下限通配符,必须是Animal的父类。
Cage<T extends Animal> 上限泛型,必须是Animal的子类
Cage<T super Animal> 没有这种用法。
Cage<?> 无限制,通配符。

4)泛型的特化
所谓泛型的特化,就是给形式化类型参数指定实际类型参数。这与类的实例化有相似之处,抽象层次不同而已。泛型之类型,正如类型之于值。泛型特化(subtyping),会产生类型擦除(type erasure)效果。类型擦除机制在编译时擦除掉所有的泛型信息,从而使得程序运行时看不见这些信息,不会影响到字节码的生成。

When a generic type is instantiated, the compiler translates those types by a technique called type erasure — a process where the compiler removes all information related to type parameters and type arguments within a class or method. Type erasure enables Java applications that use generics to maintain binary compatibility with Java libraries and applications that were created before generics.


5)泛型中的最难理解的地方
一般地,如果Foo是Bar的子类型(子类或子接口),G是一种通用的类型声明,并不意味着G<Foo> 是G<Bar>的子类型。这也许是学习泛型最难的一件事,因为其与我们根深蒂固的直觉相悖。
In general, if Foo is a subtype (subclass or subinterface) of Bar, and G is some
generic type declaration, it is not the case that G<Foo> is a subtype of G<Bar>. This is probably the hardest thing you need to learn about generics, because it goes against our deeply held intuitions.

这个看似违背直觉,其实还是存在合乎逻辑的地方。

举两个例子。
A) 水果与篮子
放水果的篮子,水果。
放苹果的篮子,苹果。

苹果与水果是“is-a"的关系,而“放苹果的篮子”与“放水果的篮子”的关系却未必是"is-a"的关系,因为篮子与篮子的关系不一定是“is-a"的关系,只是篮子里头放的东西,有"is-a"的关系。

B) 动物与笼子
关动物的笼子,动物。Cage<Animal>
关狮子的笼子,狮子。Cage<Lion>
关蝴蝶的笼子,蝴蝶。Cage<Butterfly>

显然,关狮子的笼子不能用来关蝴蝶,关蝴蝶的笼子不能用来关狮子。因为用关狮子的笼子,蝴蝶会穿过缝隙飞走;用关蝴蝶的笼子,狮子会破笼而出逃走。

//Cage<Animal> 可以关“所有动物”的笼子,
// 不能被赋值为关狮子的笼子,否则这个笼子关不住蝴蝶。
Cage<Animal> animalCage = new Cage<Lion>();

// Cage<? extends Animal> 可以关“某种动物”的笼子
// 可以被赋值为关狮子的笼子,但不能用来关狮子。
// 因为其是未知和不确定的,其可用于查询。
Cage<? extends Animal> someCage = new Cage<lion>();


import java.util.ArrayList;
import java.util.List;


class Animal {}
class Lion extends Animal {}
class Butterfly extends Animal {}

class Cage<E> {
	private List<E> cage = new ArrayList<E>();
	public void add(E e) {
		cage.add(e);
	}
	public List<E> getCage() {
		return this.cage;
	}
}

public class Test {
	public static void main(String[] args) {
		// 关狮子的笼子不能用来关蝴蝶
		Cage<Lion> lionCage = new Cage<Lion>();
		lionCage.add(new Lion()); // ok
//		lionCage.add(new Butterfly()); // compile error	
		
		//Cage<Animal> 可以关“所有动物”的笼子,
		// 不能被赋值为关狮子的笼子,否则这个笼子关不住蝴蝶。
//		Cage<Animal> animalCage = new Cage<Lion>(); // compile error
		Cage<Animal> animalCage = new Cage<Animal>();
		animalCage.add(new Lion()); // ok
		
		// Cage<? extends Animal> 可以关“某种动物”的笼子
		// 可以被赋值为关狮子的笼子,但不能用来关狮子。
		// 因为其是未知和不确定的,其可用于查询。
		Cage<? extends Animal> cage = lionCage; // ok		
//		cage.add(new Lion()); // compile error
		for (Animal animal : cage.getCage()) {
			System.out.println(animal); //ok
		}
	}
}


6)泛型与反射
泛型,是将“类型”泛化为“泛型”,从上往下赋予“类型”动态性,编译时擦除类型。(Generics, Type Erasure)
反射,是将“实例”反射为“类型”,从下往上赋予“类型”动态性,运行时确定类型。(Reflection, Type Determination)

进一步说,编程语言可向上抽象,通过“泛型”获得“动态性”;机器(语言)可向上抽象,即使编程语言可通过“反射”获得“动态性”。
分享到:
评论

相关推荐

    泛型generics.zip

    泛型(Generics)是JDK5引入的一种参数化类型特性。它提供了编译时类型安全检测机制。其本质是参数类型,所操控的数据类型被指定为一个参数。泛型不存在于JVM虚拟机。泛型学习、泛型限定类型、泛型通配符、泛型继承。...

    Java 泛型(Generics)使用说明

    环境:Windows XP Professional、JDK 1.6、Ant 1.7 说明:Java泛型的动机是为解决类型转换在编译时不报错的问题。另外由于“范型编程”(Generic Programming)的推广,于是2004年JDK 5.0引用范型标准。本例子说明...

    JDK 1.5以后的新特性

    **一、泛型 Generics** 泛型是JDK 1.5引入的一个核心特性,允许在类、接口和方法中使用类型参数,从而实现更安全、更强大的类型约束。在泛型出现之前,开发者通常使用Object作为通用类型,但这可能导致类型转换异常...

    [Java泛型和集合].(Java.Generics.and.Collections).文字版

    本资料 "[Java泛型和集合].(Java.Generics.and.Collections).Maurice.Naftalin&amp;Philip.Wadler.文字版" 由知名专家Maurice Naftalin和Philip Wadler编著,提供了关于这些主题的深入理解。 **Java泛型** 是自Java...

    Java Generics and Collections (Java泛型与集合)

    通过阅读"Java Generics and Collections",开发者不仅可以掌握Java泛型和集合的基本使用,还能深入了解它们的高级特性和最佳实践,从而在实际项目中编写出更高质量的代码。这本书对于Java程序员来说是一份宝贵的...

    .Net 2.0 泛型高级编程(Professional .NET 2.0 Generics )

    《.Net 2.0 泛型高级编程》是一本由Tod Golding编著的专业技术书籍,专注于探讨.NET Framework 2.0中的泛型特性。泛型是.NET框架中的一个重要概念,它允许开发者创建可重用的类型安全的数据结构和算法,极大地提高了...

    泛型java的泛型知识,非常有用

    - 类如 `class Java_Generics,V&gt;`,`K` 和 `V` 就是类型参数,类似于函数中的变量,它们在实例化时会被具体的类型替换。 - 示例中,`TestGen0, String&gt;` 就是泛型类的具体实例,其中 `K` 被替换为 `String`,`V` ...

    JDK 1.5的泛型實現(Generics in JDK 1.5)

    JDK 1.5的泛型實現(Generics in JDK 1.5) 1 侯捷觀點 JDK 1.5的泛型實現 — Generics in JDK 1.5 — 北京《程序員》 2004/09 台北《Run!PC》2004/09 作者簡介:侯捷,資訊教育、專欄執筆、大學教師...

    java面试常见问题(超详细).pdf

    12. **泛型Generics**: 泛型允许在类、接口和方法中使用类型参数,提高代码的类型安全性,减少强制类型转换。 13. **JVM(Java Virtual Machine)**: JVM是Java程序的运行环境,负责解释和执行字节码,实现跨...

    java 泛型类的类型识别示例

    在Java编程语言中,泛型(Generics)是一种强大的特性,它允许我们在编写代码时指定容器(如集合)可以存储的数据类型。这提高了代码的安全性和效率,因为编译器可以在编译时检查类型,避免了运行时...

    泛型编程小实例(以List为例)

    泛型(Generics)是一种在编程中引入的模板机制,用于在定义数据结构或方法时创建类型参数。这些参数可以在实例化时替换为具体的类型,使得容器(如List、Set、Map等)能够存储特定类型的元素,而不是任意类型。...

    java 泛型的使用 详细讲解

    泛型(Generics)是指在面向对象编程中,通过参数化类型来达到类型重用的目的。通俗地说,就是将类或方法中的某些类型定义为参数形式,在实际使用时再传入具体类型的机制。 ##### 2.2 为什么使用泛型? 1. **类型...

    Java1.5泛型指南中文版

    Java 1.5引入了泛型(Generics)的概念,这是一个重要的语言特性,它允许开发者在编译时期指定集合或其他数据结构中的元素类型,从而避免了运行时期的类型转换错误。通过使用泛型,开发者可以在编程阶段就确保类型的...

    泛型和方法

    在Java编程语言中,泛型(Generics)和方法是两个重要的概念,它们极大地提高了代码的类型安全性和可重用性。这篇博文将探讨这两个主题,并结合源码和工具进行深入解析。 首先,泛型是Java 5引入的一项重要特性,它...

    6-generics(泛型6).pdf

    泛型是TypeScript中的一个重要特性,它允许我们在编写代码时定义通用的类型,从而提高代码的可重用性和类型安全性。在大型系统开发中,泛型的使用是至关重要的,因为它们确保组件不仅可以处理当前的数据类型,还能...

    面试必须资料java泛型攻略、

    Java泛型(Generics)是一种在编译时确保类型安全的机制,它允许程序员编写类型安全的通用类或方法,而无需进行显式的类型转换。在Java 1.5引入泛型之前,集合类(如`ArrayList`)只能存储`Object`类型的元素。这...

    Java泛型和集合-英文版

    根据提供的文件信息,我们可以确定本书的标题为《Java泛型和集合》(Java Generics and Collections),作者为Maurice Naftalin和Philip Wadler。该书详细介绍了Java中的泛型(Generics)特性以及集合(Collections...

Global site tag (gtag.js) - Google Analytics