黑马程序员_泛型(Generic)

来源:互联网 发布:python urllib 编辑:程序博客网 时间:2024/06/11 08:09

---------------android培训java培训、期待与您交流! --------------

一,泛型的基础知识

jdk1.5之后出现的新特性

泛型是提供给javac编译器使用的,它可以限定集合中输入的类型,让编译器挡住源程序中的非法输入,编译器编译带类型的说明的集合时会去除掉"类型"信息,是程序运行效率不受影响。对应参数化的泛型类型,getClass()方法的返回值和原始类型完全一样。由于编译生成的字节码会去掉泛型的类型信息,只要能跳过编译器,就可以往某个泛型集合中加入其他类型的数据。例如用反射得到的集合,再调用add方法即可。

泛型是编译器看的,所以通过反射可以避过编译器,继续把不同的类型的值放进已经被泛型限定了的集合里面。

以ArrayList<E>为例

ArrayList称为原始类型,<>译为"typeof",ArrayList<E>称为泛型类型,E称为类型变量或者类型参数;

ArrayList<String>称为参数化的类型,String称为类型参数的实例或实际类型参数

参数化类型与原始类型全部兼容Vector v = new Vector<String>();或者:Vector<String> v = new Vector();都可以。

参数化类型不考虑类型参数的继承问题。也就是说泛型类型中的类型参数,等号两边只要不是同一种,那么编译就一定不会通过。

为什么在创建数组实例时,数组的元素不能使用参数化的类型?

编译器是严格按照步骤走的。它检测每一行代码的信息是否有误,但是不会用执行时候的答案来检测代码的正确性。

二,泛型限定:

泛型的通配符(?)应用:?表示任意类型。比如当要定义一个任意参数化类型的集合(Collection<?>col),就用得到了通配符。

使用?通配符可以引用其他各种参数化的类型,?通配符定义的变量主要用作引用,可以调用与参数化无关的方法,不能调用与参数化有关的方法。比如集合中的add()方法,使用了?的集合就不能在调用这个方法。

public void printCollection(Collection<?>col){}

也就是说Collection<?> col = new ArrayList<String>();编译器让这个表达式被编译通过。

泛型的限定:

?extends E:可以接收E类型或者E的子类。这是上限限定

?super E:可以接收E类型或者E的父类。这是下限限定

三,自定义泛型

要定义一个泛型,必须在函数的返回值之前用尖括号括起来

1、//这样声明的范型可以代替任意类型数据我们市场用到的键值对Map.Entry<K,V>不就是给予范型的吗

  KV都可以代替任意类型的值,但是在java中范型的实际类型必须是引用类型

<K,V> void get(K k,V v)
{
}

  2、Java中的范型不能像C++那么灵活

<T>  T  add(T a,T b)
{
   //return  a+b   ;//很多人以为java也想C++一样可以这样 ,但是不可以 。    
return  null;
}

  这个返回的null也是有类型限制的,比如上面的ab分别是Integer和String那么就会取他们共同的基类Object做为返回值类型,其他的同理

  3、实现任意类型的数组的成员值的交换,注意在自定义范型中范型的实际类型只能是引用数据类型不能是基本数据类型

public  static <T> void  swap(T[]a,int x,int y)
{
  T  tem  =a[x]  ;
  a[x]=a[y]  ;
  a[y]=tem ;
}

  上面这个方法如果我  swap(new Integer[]{1,2,3,4,5},1,2);       //这样就会自动交换下标12的值

  但是这样调用就错了   swao(new int[]{1,2,3,5,6},2,3) ;  //所以说Java的范型的实际类型 只能是引用数据类型

  4、<T  extends  String>     表示类型只能是String或者String的派生类
    <T super  String >   表示范型类型只能是String或者String的父类

   用法同3

  5、下面这个函数利用范型来实现类型自动转换的功能

public static  <T> T autoConvert(Object obj)  //因为返回值是 T标识任意类型 所哟可以 将返回结果赋值给任意类型对象
{
  return (T)obj;
}

Object  obj==”";

String str=autoConvert(obj);

  可以完成自动转换,因为范型T代表任意类型,因此他可以赋值给String类型的对象

6、将任意类型的对象填充到任意类型的数组中,与是fillArray(newInteger[]{2,3,4},”ddd”);这样调用是正确的,这样做忽略类型限制

public  static <T> void  fillArray(T[] a,T b)  //将任意一个对象填充到任意类型的数组
{
  for(int i =0;i<a.length;i++)
  {
   a[i] =b ;
  }
}

  7、以自定义范型的形式显示一个集合的数据,下面一个是利用自定义范型一个是利用通配符来实现,但是不同的是利用通配符操作的集合不能向集合中插入元素。

  但是自定义范型却可以。原因是通配符代表的集合我们不知道集合内部具体元素是什么类型所以不能对集合进行add操作。

public static  <T> void showCollection(Collection<T> col,T  obj)  //利用范型来输出任意类型集合

  col.add(obj) ;
  for(T a:col)
  {
   System.out.println(a);
  }
}

public static void showCollection(Collection<?> col)  //利用范型来输出任意类型集合

  for(Object obj:col)
  {
   System.out.println(obj);
  }
}

  8、如果一个类中多个方法都需要范型那么就是用类级别的范型。例如

class  A<E> 

     public void  add(E obj){}
     public  E  get(){} 
     private E data; 
}

  这样声明范型和在函数前面声明其实是一样的只不过是在类的级别上作用于整个类而已

  9、要注意范型只是给编译器看的。

  也就是说Vector<Integer>Vector<String>他们用到的都是同一份字节码,字节码只有class文件加载到内存中的时候才有

  所以在一个类中下面2个方法不能同时存在

void show(Vector<Integer>) {}
void show(Vector<String>){}

四,通过反射获得泛型的参数化类型

jdk1.5开始,一个方法可以通过反射获取到他的参数的参数化类型比如:put(Vector<Date>v),通过反射可以获取Date的类型

1.Method里面的方法:

Type[] getGenericParameterTypes()

按照声明顺序返回描述了此Method 对象所表示的方法的形参类型的 Type 对象的数组。

Type getGenericReturnType()

返回表示由此Method 对象所表示方法的正式返回类型的 Type 对象。

2.Type是接口,是ParameterizedType的父类

3.ParameterizedType 参数化类型它放的是泛型的参数化类型实例

Type[] getActualTypeArguments()

返回表示参数的类的的类型参数的Type对象数组。

Type getOwnerType()

返回Type 对象,返回此类的顶层类的类型。比如O<T>.I<S>,则返回 O<T> 的表示形式

Type getRawType()

返回Type 对象,表示声明此类型的类或接口。

---------------------- android培训java培训、期待与您交流! ----------------------

详细请查看:http://edu.csdn.net/heima

 

 

原创粉丝点击