import java.util.*; public class Generics { //无限制的通配符类型 static int numElementsInCommon(Set<?> s1, Set<?> s2) { int result = 0; for (Object o : s1) if (s2.contains(o)) result++; return result; } private Map<Class<?>, Object> favorites = new HashMap<Class<?>, Object>(); public <T> void putFavorite(Class<T> type, T instance) { if (type == null) throw new NullPointerException("Type is null"); favorites.put(type, instance); } //泛型方法 public <T> T getFavorite(Class<T> type) { return type.cast(favorites.get(type)); } public static void main(String[] args) { Generics g = new Generics(); g.putFavorite(String.class, "Java"); g.putFavorite(Integer.class, 100086); g.putFavorite(Class.class, Generics.class); String favoriteString = g.getFavorite(String.class); int favoriteInteger = g.getFavorite(Integer.class); Class<?> favoriteClass = g.getFavorite(Class.class); System.out.printf("%s %d %s%n", favoriteString, favoriteInteger, favoriteClass.getSimpleName()); Pair p = new Pair<Object> (23, "skidoo"); System.out.println(p.first() + " " + p.last()); //编译错误:因为Pair p被声明为原生类型,擦除了所有的<T>类型信息,stringList()方法返回值类型为List,而不是List<String>。 //for (String s : p.stringList()) for (Object s : p.stringList()) System.out.print(s + " "); } } class Pair<T> { private final T first; private final T last; public Pair(T first, T last) { this.first = first; this.last = last; } public T first() { return first; } public T last() { return last; } public List<String> stringList() { return Arrays.asList(String.valueOf(first), String.valueOf(last)); } } //泛型类的内部类可以访问到其外围类的类型参数。 //当你在一个泛型类中嵌套另一个泛型类时,最好为它们的类型参数设置不同的名字,即使那个嵌套类是静态的也应如此。 class LinkedList<E> { /* 访问外围类的类型参数 private Node head = null; private class Node { E value; Node next; Node(E value, Node next) { this.value = value; this.next = next; head = this; } } public void add(E e) { new Node(e); } public void dump() { for (Node n = head; n != null; n = n.next) System.out.print(n.value + " "); } */ //使用静态类 private Node<E> head = null; private static class Node<T> { T value; Node<T> next; Node(T value, Node<T> next) { this.value = value; this.next = next; } } public void add(E e) { head = new Node<E>(e, head); } public void dump() { for (Node<E> n = head; n != null; n = n.next) System.out.print(n.value + " "); } }
* java1.5增加了泛型(Generics)
泛型通用参数命名规则:T表示任意的类型,E表示结合的元素类型,K和V表示映射的键和值类型,
X表示异常,任何类型的序列可以是T、U、V或者T1、T2、T3。
* 泛型的作用:在编译时检查类型转换,而不是在运行时发现类型转换错误。
Java中的泛型只是作用于代码编译阶段,在编译过程中,对于正确检验泛型结果后,会将泛型的相关信息
擦除,也就是说,编译后的class文件中是不包含任何泛型信息的。泛型信息不会进入到运行时阶段。
* 请不要在新代码中使用原生态类型:
如果使用原生态类型就失去了泛型在安全性和表述性方面的所有优势。
使用原生态的例外情况:Class类必须使用原生态类型(List.class);instanceof操作符必须使用原生态
类型(obj instanceof List)。
* 泛型有子类型化(subtyping)的规则。List<String>是原生态类型List的一个子类型,不是List<Object>
的子类型。
* 列表优先于数组:
数组和泛型相比有两个重要的不同点:
(1) 数组是协变式的(covariant),如果Sub是Super的子类型,那么Sub[]也是Super[]的子类型。
相反,泛型是不可变的(invariant),对于任意两个不同的类型Type1和Type2,List<Type1>既不会
是List<Type2>的子类型,也不会是超类型。
(2) 数组是具体化的,因此数组会在运行时才知道并检查元素的类型约束。
泛型是通过擦除(erasure)来实现的,泛型只在编译时强化它们的类型信息,并在运行时丢弃元素
类型信息,使泛型可以与没有使用泛型的代码随意互用。
由于上述这些根本的区别,数组和泛型不能很好地混合使用。
new E[100] //编译错误:can not create a generics array of T
解决的办法:创建一个Object数组并将它转换成泛型数组类型。 (E[]) new Object[capacity]
* 无限制的通配符类型(?):如果要使用泛型,但不确定实际的参数类型,就可以使用一个问号代替。
无限制的通配符类型Set<?>与原生态类型Set的区别:可以将任何元素放入原生态类型Set中,但不能
将任何元素(除了null)放入到Set<?>中,它是类型安全的。
* 利用有限通配符类型来提升API的灵活性:? extends E 和 ? super E
类型通配符上限通过形如ClassName<? extends E>形式定义。
类型通配符下限为ClassName<? super E>形式。
extends 表示匹配E及其子类
不要用通配符类型作为泛型方法的返回类型
* JDK1.5中一个变化是类 java.lang.Class是泛型化的。这是把泛型扩展到容器类之外的一个很有意思的
例子。现在,Class有一个类型参数T, 它代表Class对象代表的类型。
比如说,String.class类型代表 Class<String>
* 消除非受检的警告:
用泛型编程时会收到许多编译器警告:unchecked cast warnings、unchecked conversion warnings等。
如果无法消除警告,同时可以保证引起警告的代码是类型安全的;可以用
@SuppressWarnings("unchecked")消除警告。应该始终在尽可能小的范围内使用@SuppressWarnings
注解。永远不要在整个类上使用,这样可能会掩盖了重要的警告。
一个原生类型很像其对应的参数化类型,但是它的所有实例成员都要被替换掉,而替换物就是这些实例
成员被擦除掉对应部分参数类型之后剩下的东西。具体地说,在一个实例方法声明中出现的每个参数化
的类型都要被其对应的原生部分所取代。
原生类型List 和参数化类型List<Object>是不一样的。如果使用了原生类型,编译器不会知道在list 允许
接受的元素类型上是否有任何限制,它会允许你添加任何类型的元素到list 中。
List<?>是一种特殊的参数化类型,被称为通配符类型(wildcard type)。
像原生类型List 一样,编译器也不会知道它接受哪种类型的元素,但是因为List<?>是一个参数化类型,
从语言上来说需要更强的类型检查。为了避免出现ClassCastException 异常,编译器不允许你添加
除null 以外的任何元素到一个类型为List<?>的list 中。
原生类型的成员被擦掉,是为了模拟泛型被添加到语言中之前的那些类型的行为。
如果你将原生类型和参数化类型混合使用,那么便无法获得使用泛型的所有好处,而且有可能产生让你
困惑的编译错误。另外,原生类型和以Object为类型参数的参数化类型也不相同。
相关推荐
本资料 "[Java泛型和集合].(Java.Generics.and.Collections).Maurice.Naftalin&Philip.Wadler.文字版" 由知名专家Maurice Naftalin和Philip Wadler编著,提供了关于这些主题的深入理解。 **Java泛型** 是自Java...
综上所述,虽然Java泛型在编译后会进行类型擦除,但通过上述技巧,我们仍然能够在运行时获得关于泛型类实例化类型的一些信息。在实际开发中,这些方法可以帮助我们编写更加灵活和安全的代码。在示例文件`GenericRTTI...
通过阅读"Java Generics and Collections",开发者不仅可以掌握Java泛型和集合的基本使用,还能深入了解它们的高级特性和最佳实践,从而在实际项目中编写出更高质量的代码。这本书对于Java程序员来说是一份宝贵的...
Java泛型(Generics)是一种在编译时确保类型安全的机制,它允许程序员编写类型安全的通用类或方法,而无需进行显式的类型转换。在Java 1.5引入泛型之前,集合类(如`ArrayList`)只能存储`Object`类型的元素。这...
[Java泛型和集合].(Java.Generics.and.Collections).Maurice.Naftalin&Philip.Wadler.文字版.pdf
环境:Windows XP Professional、JDK 1.6、Ant 1.7 说明:Java泛型的动机是为解决类型转换在编译时不报错的问题。另外由于“范型编程”(Generic Programming)的推广,于是2004年JDK 5.0引用范型标准。本例子说明...
### Java泛型的使用详细讲解 #### 一、引言 在Java开发中,泛型是一种重要的语言特性,它能够帮助开发者在不增加代码量的情况下处理多种数据类型,同时还能保持代码的清晰度和可读性。本文将详细介绍Java泛型的...
Java泛型与容器详细笔记涉及到Java编程语言中的两个重要概念:泛型(Generics)和容器(Containers)。容器主要包括Java集合框架中的各类集合类,如List、Set、Map等,它们用于存储和操作数据。泛型则提供了一种类型...
《Java泛型与集合》由Maurice Naftalin与Philip Wadler合著,是一部深入探讨Java泛型和集合框架的专业书籍。本书系统地介绍了Java泛型的基础知识、高级特性以及集合框架的使用方法,旨在帮助开发者更好地理解和运用...
Java泛型(Generics)是Java SE 5.0引入的一项重要新特性,它允许开发者在定义类、接口或方法时使用类型参数(Type Parameters)。类型参数在使用时可以用具体的类型来替代。这一特性的引入极大地增强了Java集合框架...
### Java泛型编程快速入门详解 #### 一、Java泛型概述 Java泛型是Java 5.0引入的一个重要特性,它允许开发者在编译时检查类型安全,并且所有的强制转换都是自动和隐式的,提高了代码的重用率。 ##### 1.1 Java...
根据提供的文件信息,我们可以确定本书的标题为《Java泛型和集合》(Java Generics and Collections),作者为Maurice Naftalin和Philip Wadler。该书详细介绍了Java中的泛型(Generics)特性以及集合(Collections...
感谢所有为Java泛型做出贡献的人们,包括设计者、实现者以及提供反馈和支持的社区成员。泛型是Java语言的一个重要特性,极大地提高了代码的质量和可维护性。 以上就是基于给定文件信息对Java 1.5泛型指南的主要知识...
Java泛型是JDK 1.5引入的重要特性,它为Java编程提供了类型安全的集合框架,使得在编译时期就能进行类型检查,避免了运行时的类型转换风险,极大地提高了代码的可读性和健壮性。泛型的引入是为了在不牺牲面向对象...