1、 泛型为JDK1.5 之后出现的新特性,类中的属性类型由外部定义,而且在声明类的时候应该采取下面形式:
class 类名称 < 泛型类型,泛型类型, ...>{
}
如下类Point :
package com.chenzehe.test; public class Point<T> { // T为泛型类型,也可以由其它字母声明 private T x ; private T y ; public T getX() { return x ; } public void setX(T x) { this . x = x; } public T getY() { return y ; } public void setY(T y) { this . y = y; } }
程序中属性的类型不再由程序中设定,而是由实例化对象的时候在外部指定。
在没有泛型之前,从集合中读取到每个对象都必须进行转换,如果不小心插入了类型错误的对象,只有在运行到转换的地方才会出现错误。有了泛型之后,可以告诉编译器每个集合中接受哪些对象类型,在编译的时候就能知道插入的类型是否正确。
2、 泛型擦除
如果在使用泛型的时候没有指定泛型类型,则表示擦除泛型,class<T> 将按照 Object 类型进行接收,保证程序不出错,如下:
package com.chenzehe.test; public class Test { public static void main(String[] args) { Point point = new Point (); point.setX(10) ; point.setY(20) ; } }
但是该程序会出现警告信息,要想去掉警告信息,则指定 T为 Object 类型,如
Point <Object> point = new Point <Object>();
但是这种程序没有任何意义,在开发中建议不要擦除泛型。
每全泛型都定义一个原生态类型(raw type),即不带任何实际类型参数的泛型名称,如List<T>相对应的原生态类型就是List,原生态类型就像从类型声明中删除所有泛型信息一样。
在jdk 1.5之前,有如下代码:
private final Collection stamps=... ;
如果不小心将一个Coin类型对象放到stamp集合中,这种错误在编译时不会出现任何错误:
stamps.add(new Coin(...));
for (Iterator i = stamps.iterator() ; i.hasNext();){ Stamp s = (Stamp) i.next(); }
private final Collection<Stamp> stamps = ... ;
如果插入的对象类型不是Stamp编译器就会报错而不用等到运行到该行代码才出错。
如上所述,如果不提供类型参数,使用集合类型和其它泛型也仍然是合法的,但是不应该这么做,如果使用原生态类型,就失掉了泛型在安全性和表述性方面的优势。既然不应该这么做,但是为什么jdk中还允许呢,这是为了提供兼容性,因为泛型出现的时候,已经存在没有使用泛型的大量java代码,人们认为让所有这些代码保持合法,并且能够与使用泛型的代码互用。
3、 泛型通配符?
如下程序:
Integer integer = new Integer(10); Object obj = integer;
可以进行向上转型,而对于泛型中定义的类型则不能向上转型,如:
Point<Object> objectPoint = new Point<Object>(); Point<Integer> integerPoint = new Point<Integer>(); objectPoint = integerPoint ; // 不能向上转型
如下代码,在调用 print函数时不能向上转型而出错:
package com.chenzehe.test; public class Test { public static void main(String[] args) { Point<Object> objectPoint = new Point<Object>(); Point<Integer> integerPoint = new Point<Integer>(); print (objectPoint); print (integerPoint); //不能向上转型,调用出错 } public static void print(Point<Object> p) { System. out .println(p.getX()); System. out .println(p.getY()); } }
要想实现调用,则可以在声明函数参数时使用擦除泛型的方式,如下:
public static void print(Point p) { System. out .println(p.getX()); System. out .println(p.getY()); }
这样 print (integerPoint); 就可以实现调用,但是 print函数声明还是有警告信息,并且在使用时转型还可能出现异常,最好的解决方法是声明 print 函数时使用泛型通配符?,如:
public static void print(Point< ? > p) { System. out .println(p.getX()); System. out .println(p.getY()); }
?表示可以接收任何泛型,但是使用泛型通配符时,该类型对象只有可读属性,没有可写属性,如上面p.getX() 方法可以使用,但是 set 方法不能使用,如 p. setX (123); 不可以使用。
泛型通配符和原生态类型间有什么区别?泛型通配符是类型安全的,原生态类型是不安全的。
虽然不应该在代码中使用像List这样的原生态类型,使用参数化的类型以允许插入任意对象,如List<Object>,这样还是可以的。不严格的来说,原生态类型逃避了类型检察,而List<Object>告诉编译器他能够持有任意类型的对象。虽然你可以将List<String>传递给类型List的参数,但是不能将他传递给类型List<Object>的参数。
4、 泛型上限
指泛型类型可以指定的最大的父类,如将上限设置为Number 类型,则此时可以接收的泛型类型只能为 Number 或其子类 Integer 等,语法为:
Class <T extends 父类 >
如将上面Point 类泛型设置为最后只能是 Number 类型:
package com.chenzehe.test; public class Point< T extends Number> { // T 只能为 Number类型或其子类 private T x ; private T y ; public T getX() { return x ; } public void setX( T x) { this . x = x; } public T getY() { return y ; } public void setY( T y) { this . y = y; } }
在使用该泛型时, Point<Integer> integerPoint = new Point<Integer>(); 可以使用,而 Point< String > stringPoint = new Point< String >(); 则不能使用。
泛型上限也可以在方法上使用,如下面在接收参数时使用:
package com.chenzehe.test; public class Test { public static void main(String[] args) { Point<Integer> integerPoint = new Point<Integer>(); print (integerPoint); } public static void print(Point<? extends Number > p) { System. out .println(p.getX()); System. out .println(p.getY()); } }
5、 泛型下限
指泛型只能设置其具体的类或者父类,使用super 关键字定义,在定义泛型类型时不能使用泛型下限,只有在使用时才能定义下限,如:
Point类要定义成 public class Point<T super Integer> 则报错,但是在 print方法中可以定义,如:
public static void print(Point<? super Integer > p) { System. out .println(p.getX()); System. out .println(p.getY()); }
6、 泛型接口
泛型不但可以作用在类上,还可以作用在接口上,定义如下:
interface 接口名称 < 泛型类型 , 泛型类型 ,...>
如下实例定义泛型接口IDemo :
package com.chenzehe.test; public interface IDemo<T> { void print ( T param ) ; }
有两种方式可以实现该接口,方式一:实现类不指定具体泛型类型
package com.chenzehe.test; public class DemoImpl<T> implements IDemo<T> { public void print ( T param ) { System. out .println ( "param = " + param ) ; } }
方式二:实现类指定具体泛型类型
package com.chenzehe.test; public class DemoImpl implements IDemo< String > { public void print ( String param ) { System. out .println ( "param = " + param ) ; } }
7、 泛型方法
泛型还可以定义在方法上,在方法中使用泛型,该方法所在的类不一定是泛型操作类。如:
package com.chenzehe.test; public class Demo { public <T> T print ( T param ) { return param ; } }
也可以将方法返回值定义成泛型数组:
public <T> T [] Print ( T... params ) { return params; }
8、 泛型嵌套设置
定义Info 类:
package com.chenzehe.test; public class Info<T> { private T param ; public T getParam () { return this . param ; } public void setParam ( T param ) { this . param = param; } }
定义Person 类:
package com.chenzehe.test; public class Person< T > { private T info ; public T getInfo () { return this . info ; } public void setInfo ( T info ) { this . info = info; } }
测试类:
package com.chenzehe.test; public class Test { public static void main ( String [] args ) { Person<Info<String>> person = new Person<Info<String>> () ; person.setInfo ( new Info<String> ()) ; person.getInfo () .setParam ( "chenzehe" ) ; System. out .println ( person.getInfo () .getParam ()) ; } }
9、 消除非受检警告
在使用泛型编程时,会遇到许多编译器警告:非受检强制转化警告(unchecked cast warnings)、非受检方法调用警告、以及非受检转换警告(unchecked conversion warnings)。
有许多非受检警告很容易消除,如下面的警告:
Set<Lark> exaltation = new HashSet();
Set<Lark> exaltation = new HashSet<Lark>();
10、列表优先于数组
数组与泛型相比有两个重要的不同点,首先,数组是协变的(covariant),表示如果Sub为Super的子类型,那么数组类型Sub[]就是Super[]的子类型,相反泛型是不可变的(invariant),表示对于任意两个不同的类型Type1和Type2,List<Type1>即不是List<Type2>的子类型,也不是List<Type2>的父类型。
下在代码是合法的:
// Fails at runtime Object[] objectsArray = new Long[1]; objectsArray[0] = "I don't fit in"; // Throws ArrayStoreException
// Won't compile! List<Object> ol = new ArrayList<Long>(); // Incompatible types ol.add("I don't fit in");
import java.util.Arrays; import java.util.EmptyStackException; /** * Huisou.com Inc. Copyright (c) 2011-2012 All Rights Reserved. */ public class Stack { private Object[] elements; private int size = 0; private static final int DEFAULT_INITIAL_CAPACITY = 16; public Stack() { elements = new Object[DEFAULT_INITIAL_CAPACITY]; } public void push(Object e) { ensureCapacity(); elements[size++] = e; } public Object pop() { if (0 == size) { throw new EmptyStackException(); } Object result = elements[--size]; elements[size] = null;// 不设置为null可能导致内存溢出 return result; } public boolean isEmpty() { return size == 0; } private void ensureCapacity() { if (elements.length == size) { elements = Arrays.copyOf(elements, 2 * size + 1); } } }
import java.util.Arrays; import java.util.EmptyStackException; /** * Huisou.com Inc. Copyright (c) 2011-2012 All Rights Reserved. */ public class Stack<E> { private E[] elements; private int size = 0; private static final int DEFAULT_INITIAL_CAPACITY = 16; public Stack() { elements = new E[DEFAULT_INITIAL_CAPACITY]; } public void push(E e) { ensureCapacity(); elements[size++] = e; } public E pop() { if (0 == size) { throw new EmptyStackException(); } E result = elements[--size]; elements[size] = null;// 不设置为null可能导致内存溢出 return result; } public boolean isEmpty() { return size == 0; } private void ensureCapacity() { if (elements.length == size) { elements = Arrays.copyOf(elements, 2 * size + 1); } } }
elements = new E[DEFAULT_INITIAL_CAPACITY];
elements =(E[]) new Object[DEFAULT_INITIAL_CAPACITY];
@SuppressWarnings("unchecked") public Stack() { elements = (E[]) new Object[DEFAULT_INITIAL_CAPACITY]; }
private Object[] elements; public Stack() { elements = new Object[DEFAULT_INITIAL_CAPACITY]; }
E result = elements[--size];
E result = (E) elements[--size];
public E pop() { if (0 == size) { throw new EmptyStackException(); } @SuppressWarnings("unchecked") E result = (E) elements[--size]; elements[size] = null;// 不设置为null可能导致内存溢出 return result; }
相关推荐
Java泛型的用法及T.class的获取过程解析 Java泛型是Java编程语言中的一种重要特性,它允许开发者在编写代码时指定类型参数,从而提高代码的灵活性和可读性。本文将详细介绍Java泛型的用法 及T.class的获取过程解析...
Java 泛型详解 Java 泛型是 Java SE 5.0 中引入的一项特征,它允许程序员在编译时检查类型安全,从而减少了 runtime 错误的可能性。泛型的主要优点是可以Reusable Code,让程序员编写更加灵活和可维护的代码。 ...
Java泛型是Java编程语言中的一个强大特性,它允许我们在定义类、接口和方法时指定类型参数,从而实现代码的重用和类型安全。在Java泛型应用实例中,我们可以看到泛型如何帮助我们提高代码的灵活性和效率,减少运行时...
Java泛型机制详解 Java泛型是Java语言中的一种机制,用于在编译期检查类型安全。Java泛型的出现解决了Java早期版本中类型安全检查的缺陷。Java泛型的好处是可以在编译期检查类型安全,避免了运行时的...
综上所述,虽然Java泛型在编译后会进行类型擦除,但通过上述技巧,我们仍然能够在运行时获得关于泛型类实例化类型的一些信息。在实际开发中,这些方法可以帮助我们编写更加灵活和安全的代码。在示例文件`GenericRTTI...
Java泛型是Java编程语言中的一个关键特性,它在2004年随着Java SE 5.0的发布而引入,极大地增强了代码的类型安全性和重用性。本篇文章将深入探讨Java泛型的发展历程、核心概念以及其在实际开发中的应用。 1. **发展...
Java泛型是Java编程语言中的一个关键特性,它在2004年随着JDK 5.0的发布被引入。这个特性极大地提高了代码的类型安全性和可读性,减少了在运行时出现ClassCastException的可能性。SUN公司的Java泛型编程文档,包括...
下面我们将详细探讨Java泛型接口的相关知识点。 1. **泛型接口的定义** 泛型接口的定义方式与普通接口类似,只是在接口名之后添加了尖括号`<T>`,其中`T`是一个类型参数,代表某种未知的数据类型。例如: ```java...
下面我们将深入探讨Java泛型方法的概念、语法以及使用示例。 **一、泛型方法概念** 泛型方法是一种具有类型参数的方法,这些类型参数可以在方法声明时指定,并在方法体内部使用。与类的泛型类似,它们提供了编译时...
Java泛型是Java编程语言中的一个强大特性,它允许在定义类、接口和方法时使用类型参数,从而实现参数化类型。这使得代码更加安全、可读性更强,并且能够减少类型转换的必要。在“java泛型的内部原理及更深应用”这个...
这是一个使用JAVA实现的泛型编程,分为两部分,第一部分创建泛型类,并实例化泛型对象,得出相加结果。 第二部分用户自行输入0--4,选择要进行的加减乘除运算或退出,再输入要进行运算的两个数,并返回运算结果及...
Java 泛型是一种强大的工具,它允许我们在编程时指定变量的类型,提供了编译时的类型安全。然而,Java 的泛型在运行时是被擦除的,这意味着在运行时刻,所有的泛型类型信息都会丢失,无法直接用来创建对象或进行类型...
"Java 泛型学习" Java 泛型是 Java 语言的类型系统的一种扩展,以支持创建可以按类型进行参数化的类。泛型的主要目标是提高 Java 程序的类型安全。通过知道使用泛型定义的变量的类型限制,编译器可以在一个高得多的...
Java 泛型使用详细分析 Java 泛型是 Java 语言中的一种类型系统特性,允许开发者在编译期检查类型安全,以避免在运行时出现类型相关的错误。在本文中,我们将详细介绍 Java 泛型的使用方法和实现原理。 一、泛型的...
Java泛型是Java编程语言中的一个关键特性,它在2004年随着Java SE 5.0的发布而引入,极大地增强了代码的类型安全性和重用性。本篇文章将深入探讨Java泛型的发展历程、核心概念以及其在实际开发中的应用。 1. **发展...
#### 一、什么是Java泛型? Java泛型(Generics)是一种在编译时确保类型安全的机制,它允许程序员编写类型安全的通用类或方法,而无需进行显式的类型转换。在Java 1.5引入泛型之前,集合类(如`ArrayList`)只能...