class GenClass<T>{
T ob;
GenClass(T o){
this.ob = o;
}
T getOb(){
return this.ob;
}
void showType(){
System.out.println("Type of T is " + ob.getClass().getName());
}
}
public class GenDemo {
public static void main(String args[]){
GenClass<Integer> iObject = new GenClass<Integer>(88);
iObject.showType();
}
}
这段代码的输出为:
Type of T is java.lang.Integer
【*:上边定义了一个带泛型的类,在使用的时候T可以替换为所有我们需要的类型,这种定义方式类似C++里面的模板定义。】
2)深入理解泛型:
【*:这里仅仅提供一般初学者和一些开发人员能够理解的泛型知识】
[1]数据类型转换:
在前边《Java的类和对象》章节里面已经说过了,Java里面存在类的向下转型和向上转型,而且Java语言里面有时候比较容易因为类型的检查引发转型的问题,因为很多时候需要不断地向下转型,这种方式往往增加了JVM的一部分运行时的开销。实际上程序中每个向下转型针对ClassCastException都是潜在的危险, 应当尽量避免它们,但是在写程序的过程,这种转型往往没有办法避免,即使特别优良的设计也是会存在的。其实JDK 1.4到JDK 1.5的升级过程泛型是一个大的跨度,这种跨度使得编写程序更加规范,其实在前边讲解集合的时候已经使用了很多泛型的编程格式了,提供的很多代码Demo 都是泛型的。这里再提供一段简单的泛型使用代码:
——[$]使用泛型的 List——
package org.susan.java.generic;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
/**
*泛型List的使用,结合了JDK 1.4和JDK 1.5的两种用法,但是在JDK 1.4编译器中下边的方式编不通
**/
public class ListGenericDemo {
public static void main(String args[]){
List list = new ArrayList();
List<String> genList = new ArrayList<String>();
list.add("List 1");
list.add("List 2");
genList.add("Generic List 1");
genList.add("Generic List 2");
System.out.println("No Generic:");
Iterator iterator = list.iterator();
while(iterator.hasNext()){
System.out.print("[" + (String)iterator.next() + "],");
}
System.out.println("\nGeneric:");
Iterator<String> genIterator = genList.iterator();
while(genIterator.hasNext()){
System.out.print("[" + genIterator.next() + "],");
}
}
}
上边这段代码的输出为:
No Generic:
[List 1],[List 2],
Generic:
[Generic List 1],[Generic List 2],
这里使用了两种不同的方式【*: 在最原始的定义的List参数里面,不使用泛型的时候都是直接使用Object类型,在传入String的时候会进行向下转型,一般情况不会出现转型失败 的情况,但是使用了泛型过后,就上边的genList代码段里面,只能添加String对象,如果使用了其他类型的元素这里编译器就会直接报错,这种做法消除了JVM本身的类型转换。】
[2]基本类型限制
Tiger【Java 5.0的版本号】中 的类型变量的限制之一就是:必须使用引用类型进行实例化,基本类型不起作用,就是说不能使用:List<int> list = new ArrayList<int>();这种定义方式。也就是说在泛型使用的过程里面,如果要针对基本类型进行泛型使用,必须要进行包装,就是 Boxing操作,比如把int包装成为Integer。
这里参考以下泛型的类型限制:JSR-14中:
public class GenGonsDemo {
public static void main(String args[]){
GenGons genOne = new GenGons(100);
GenGons genTwo = new GenGons(123.5F);
genOne.showVal();
genTwo.showVal();
}
}
这段程序输出为:
Val: 100.0
Val: 123.5
[4]泛型中通配符的使用:
通配符——使 用一个?标识类型参数,是一种表示未知类型的约束方法。通配符并不包含在最初的泛型设计中,从形成JSR14到发布其最终版本之间的五年时间内完成了设计 添加到泛型中。通配符在泛型的使用中具有重要的意义,它们为一个泛型类所指定的类型集合提供了一个有用的类型范围。对泛型的ArrayList而言,对于 任意类型T,ArrayList<?>类型是ArrayList<T>的超类型,但是这些超类型在执行类型推断方面是不起作用的。通配符类型List<?>、原始List和具体List<Object>都不相同。如果说变量X具有List<?>类型,标识存在一些T类型,其中x是List<T>类型,x具有相同的结构,尽管我们不知道其元素的具体类型。这并不代表它具有任意内容,而是指我们并不了解内容的类型限制是什么 — 但我们知道存在 某种限制。另一方面,原始类型 List 是异构的,我们不能对其元素有任何类型限制,具体类型 List<Object> 表示我们明确地知道它能包含任何对象(当然,泛型的类型系统没有 “列表内容” 的概念,但可以从 List 之类的集合类型轻松地理解泛型)。 通配符在类型系统中的作用部分来自其不会发生协变(covariant)这一特性。数组是协变的,因为 Integer 是 Number 的子类型,数组类型 Integer[] 是 Number[] 的子类型,因此在任何需要 Number[] 值的地方都可以提供一个 Integer[] 值。另一方面,泛型不是协变的, List<Integer> 不是 List<Number> 的子类型,试图在要求 List<Number> 的位置提供 List<Integer> 是一个类型错误。这不算很严重的问题,也不是所有人都认为的错误,但泛型和数组的不同行为的确引起了许多混乱。
——[$]通配符的使用 ——
package org.susan.java.generic;
class Status<T extends Number>{
T[] nums;
Status(T[] o){
nums = o;
}
double average(){
double sum = 0.0;
for( int i = 0; i < nums.length; i++)
sum += nums[i].doubleValue();
return sum / nums.length;
}
boolean sameAvg(Status<?> obj){
if( average() == obj.average())
return true;
return false;
}
}
public class WildcardDemo {
public static void main(String args[]){
Integer inums[] = {1,2,3,4,5};
Status<Integer> iobj = new Status<Integer>(inums);
System.out.println("iob average is "+ iobj.average());
Double dnums[] = {1.1,2.2,3.3,4.4,5.5};
Status<Double> dobj = new Status<Double>(dnums);
System.out.println("dob average is "+ dobj.average());
Float fnums[] = {1.1F,2.2F,3.3F,4.4F,5.5F};
Status<Float> fobj = new Status<Float>(fnums);
System.out.println("fob average is "+ fobj.average());
}
}
这段程序的输出为:
iob average is 3.0
dob average is 3.3
fob average is 3.300000023841858
——[$]返回泛型值的方法——
package org.susan.java.generic;
import java.io.Serializable;
class Base{}
class SubClass extends Base implements Serializable{}
class SubClassTwo extends Base implements Serializable{}
public class TypeInference {
public static <T extends Base> T Method(T t1,T t2){
return null;
}
public static void main(String args[]){
Base base = Method(new SubClass(), new SubClassTwo());
Serializable run = Method(new SubClass(), new SubClassTwo());
}
}
注意上边返回值的写法
——[$]?通配符——
package org.susan.java.generic;
import java.util.ArrayList;
import java.util.List;
/**
*问号通配符
**/
public class QuestionDemo {
private static void testMethod(List<? extends Number> list){}
public static void main(String args[]){
List<Object> oList = new ArrayList<Object>();
List<Integer> iList = new ArrayList<Integer>();
List<Number> nList = new ArrayList<Number>();
//testMethod(oList); //这里会出现编译错误
testMethod(iList);
testMethod(nList);
}
}
从上边的的代码可以知道,?一般和extends以及super关键字进行使用,其含义在于传入泛型的类型定义为extends后边的类型的子类,所以上边的注释掉的代码是没有办法通过编译的。
【*:泛型真正在开发过程程序员需要掌握的是用法,上边讲到的四点都比较深入,而且都是讨论的与JVM处理泛型原理相关的内容,如果没有弄懂没有关系,下边讲“泛型类型捕获”的时候主要提及应用层的相关内容。】
——[$]定义一个泛型接口——
package org.susan.java.generic;
interface MinMan<T extends Comparable<T>>{
T min();
T max();
}
class MyDemo<T extends Comparable<T>> implements MinMan<T>{
T[] tValues;
MyDemo(T[] o){ tValues = o;}
public T min(){
T vT = tValues[0];
for( int i = 1; i < tValues.length; i++ )
if(tValues[i].compareTo(vT) < 0)
vT = tValues[i];
return vT;
}
public T max(){
T vT = tValues[0];
for( int i = 1; i < tValues.length; i++ )
if(tValues[i].compareTo(vT) > 0)
vT = tValues[i];
return vT;
}
}
public class GenericInterface {
public static void main(String args[]){
Integer inums[] = {3,6,13,11,45,22,33,21};
MyDemo<Integer> iob = new MyDemo<Integer>(inums);
System.out.println("iob Max:" + iob.max());
System.out.println("iob Min:" + iob.min());
}
}
该输出为:
iob Max:45
iob Min:3
——[$]泛型的方法重载——
package org.susan.java.generic;
/**
*一段错误的代码段
**/
class MyGenDemo<T,V>{
T ob1;
V ob2;
void set(T o){
this.ob1 = o;
}
void set(V o){
this.ob2 = o;
}
}
class GenDemo<T>{
T ob;
GenDemo(){
this.ob = new T();
}
}
class Wrong<T>{
static T ob;
static T getOb(){
return ob;
}
}
分析上边的代码段就可以发现很多问题:
//这里编译报错,iList是List<Integer>,不是 List<Number>
//methodOne(iList);
methodTwo(iList);
methodThree(iList);
//这里编译报错,iList不满足条件List<? super Number>,因为List<Integer>中外露类型Integer不满足Integer super Number
//methodFour(iList);