理解Java泛型
2014-04-28 11:03
351 查看
1.为什么要用泛型(generics)?
1)在编译时纠错;2)省去了转型;3)可以使用泛型方法。
2.泛型类型
泛型类型是类或接口,这些类或接口的类型是参数化(parameterized)的,被称为类型参数(type parameters),它对应的实参是类型(type),而普通参数(formal parameters)对应的实参是值(value)。
3.泛型类
定义:class ClassName<T1, T2, ..., Tn> { ... }
尖括号里的T1, T2, ..., Tn就是类型参数。
实例化泛型类:ClassName<type> objectName;
这里的type是类型实参(type argument),如类类型、接口类型、数组类型,但是不能是基本数据类型。
例子:
4.泛型方法
和型类类似,只是作用于局限在声明它的方法中。
在这里inspect 为泛型方法,它定义一个名为U的类型参数,这个方法接受一个对象,把对象的类型发送到标准输出。该程序的结果:
T: java.lang.Integer
U: java.lang.String
5.受限类型参数(bounded typeparameter)
有时候我们需要限制传递给类型参数的类型种类,例如对数字进行操作的方法可能只希望接受Number或其子类的实例。这就是受限类型参数的用途。
用法:<T extends UpperBound>,UpperBound指的是上限。
前一小节的例子中inspect的实参可以使任何类型的(除基本数据类型),但是这里的例子中inspect的实参只能是Number极其子类型,否则会变异失败。
一个类型参数也可以有多个上限,使用&连接,但是要注意上限是类名的必须放在前面。
Class A { /* ... */ }
interface B { /* ... */ }
interface C { /* ... */ }
class D <T extends A & B & C>{ /* ... */ }
6.通配符
在泛型中,通配符“?”表示未知类型。
1)非受限的通配符“<?>”
它一般指两种情况下使用:
i.方法是通过Object的函数实现的。
ii.泛型类的方法不依赖于类型参数,例如 List.size或List.clear。
上面的例子中,对于任意的特定类型A,list<A>都是list<?>的子类型,所以可以用printList打印任何类型。
这里Arrays.asList方法表示将特定的数组转换成特定大小的List。
2)有上限的通配符“<?extends A>”
输出结果是6.0。
3)有下限的通配符“<? super A>”
下面的程序将1~10添加到List中:
5.类型擦出(type erasure)
虚拟机中并没有泛型类型对象,所有的对象都是一样的,都属于普通的类。由于JVM根本不支持泛型类型,是编译器“耍了个花招”,使得似乎存在对泛型类型的支持——它们用泛型类型信息检查所有的代码,但随即“擦除”所有的泛型类型并生成只包含普通类型的类文件。泛型类在Java源码上看起来与一般的类不同,在执行时被虚拟机翻译成对应的“原始类型”。泛型类的类型参数列表被去掉,虚拟机用类型参数的限定类型对使用类型参数的地方进行了替换,如果没有限定类型则使用Object类型进行替换。这个过程就是所谓的“类型擦除”。类型参数如果有多个限定,则使用第一个限定类型做替换。泛型方法也会做相同的替换。(摘自nothing0318的博客)
java编译器实现类型擦除的过程:
i.将类型参数用他们的上限或下限代替,没有上下限是用Object代替。
ii.如果需要的话使用转型来保证类型安全
iii.在扩展的泛型类中使用桥接方法来保留多态性。
1)在编译时纠错;2)省去了转型;3)可以使用泛型方法。
2.泛型类型
泛型类型是类或接口,这些类或接口的类型是参数化(parameterized)的,被称为类型参数(type parameters),它对应的实参是类型(type),而普通参数(formal parameters)对应的实参是值(value)。
3.泛型类
定义:class ClassName<T1, T2, ..., Tn> { ... }
尖括号里的T1, T2, ..., Tn就是类型参数。
实例化泛型类:ClassName<type> objectName;
这里的type是类型实参(type argument),如类类型、接口类型、数组类型,但是不能是基本数据类型。
例子:
public class Box<T> { // T stands for "Type" privateT t; public void set(T t) { this.t = t; } publicT get() { return t; }
public class BoxDemo { public static void main(String []args){ Box<Integer> integerBox = newBox<Integer>; integerBox.add(new Integer(10)); Integer someInteger = integerBox.get();//不需要转型 System.out.println(someInteger);} }
4.泛型方法
和型类类似,只是作用于局限在声明它的方法中。
public class Box<T> { private T t; public void set(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.set(new Integer(10)); integerBox.inspect("some text"); } }
在这里inspect 为泛型方法,它定义一个名为U的类型参数,这个方法接受一个对象,把对象的类型发送到标准输出。该程序的结果:
T: java.lang.Integer
U: java.lang.String
5.受限类型参数(bounded typeparameter)
有时候我们需要限制传递给类型参数的类型种类,例如对数字进行操作的方法可能只希望接受Number或其子类的实例。这就是受限类型参数的用途。
用法:<T extends UpperBound>,UpperBound指的是上限。
public class Box<T> { privateT t; public void set(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.set(new Integer(10)); integerBox.inspect("some text"); // 出错!实参是String不是Number。 } }
前一小节的例子中inspect的实参可以使任何类型的(除基本数据类型),但是这里的例子中inspect的实参只能是Number极其子类型,否则会变异失败。
一个类型参数也可以有多个上限,使用&连接,但是要注意上限是类名的必须放在前面。
Class A { /* ... */ }
interface B { /* ... */ }
interface C { /* ... */ }
class D <T extends A & B & C>{ /* ... */ }
6.通配符
在泛型中,通配符“?”表示未知类型。
1)非受限的通配符“<?>”
它一般指两种情况下使用:
i.方法是通过Object的函数实现的。
ii.泛型类的方法不依赖于类型参数,例如 List.size或List.clear。
public static void printList(List<?>list) { for (Object elem: list) System.out.print(elem + ""); System.out.println(); }
上面的例子中,对于任意的特定类型A,list<A>都是list<?>的子类型,所以可以用printList打印任何类型。
List<Integer> li = Arrays.asList(1,2, 3); List<String> ls = Arrays.asList("one","two", "three"); printList(li); printList(ls);
这里Arrays.asList方法表示将特定的数组转换成特定大小的List。
2)有上限的通配符“<?extends A>”
public static double sumOfList(List<?extends Number> list) { double s = 0.0; for (Number n : list) s += n.doubleValue(); return s; }
List<Integer> li = Arrays.asList(1,2, 3); System.out.println("sum = " +sumOfList(li));
输出结果是6.0。
3)有下限的通配符“<? super A>”
下面的程序将1~10添加到List中:
public static void addNumbers(List<?super Integer> list) { for (int i = 1; i <= 10; i++) { list.add(i); } }
5.类型擦出(type erasure)
虚拟机中并没有泛型类型对象,所有的对象都是一样的,都属于普通的类。由于JVM根本不支持泛型类型,是编译器“耍了个花招”,使得似乎存在对泛型类型的支持——它们用泛型类型信息检查所有的代码,但随即“擦除”所有的泛型类型并生成只包含普通类型的类文件。泛型类在Java源码上看起来与一般的类不同,在执行时被虚拟机翻译成对应的“原始类型”。泛型类的类型参数列表被去掉,虚拟机用类型参数的限定类型对使用类型参数的地方进行了替换,如果没有限定类型则使用Object类型进行替换。这个过程就是所谓的“类型擦除”。类型参数如果有多个限定,则使用第一个限定类型做替换。泛型方法也会做相同的替换。(摘自nothing0318的博客)
java编译器实现类型擦除的过程:
i.将类型参数用他们的上限或下限代替,没有上下限是用Object代替。
ii.如果需要的话使用转型来保证类型安全
iii.在扩展的泛型类中使用桥接方法来保留多态性。
相关文章推荐
- Java泛型中extends和super的理解
- Java泛型深入理解
- Java泛型的理解
- java相关求助---Java泛型的理解与等价实现---------没有完全明白啊...请大神指导...
- Java泛型的理解
- Java泛型 extends,super和通配符的理解
- 初步理解的就JAVA泛型
- java泛型的理解
- Java泛型中extends和super的理解
- Java泛型中通配符的几点理解
- java泛型擦除的理解
- Java泛型的理解和用法
- 深入理解java泛型
- Java泛型中extends和super的理解(转)
- 理解Java泛型方法
- Java泛型深入理解
- java泛型的理解
- JVM如何理解Java泛型类(转)
- 深入理解java泛型
- Java泛型深入理解