泛型知识点

来源:互联网 发布:克服恐惧知乎 编辑:程序博客网 时间:2024/06/05 06:11

泛型:

                ArrayList<String> coll2 = new ArrayList<String>();
  coll2.add("kkk2");
  System.out.println(coll2.get(0));
  
  ArrayList<Integer> coll3 = new ArrayList<Integer>();
  System.out.println(coll3.getClass()== coll2.get//返回结果为true;

泛型是提供给JAVAC编译器使用的,可以限定集合中的输入类型,让编译器挡住源程序中的非法输入,
编译器编译带类型说明的集合时回去掉“类型”信息,使程序运行效率不受影响,对于参数化的泛型类型,getClass()方法的返回值和袁术类型完全一样。由于编译生成的字节码会去掉泛型

的类型信息,只要
能跳过编译器,就可以往某个泛型集合中加入其他类型数据,例如,用反射得到集合,再调用其add方法即可。


//在Integer类型中插入字符串格式数据
                 ArrayList<Integer> coll3 = new ArrayList<Integer>();
  coll3.getClass().getMethod("add", Object.class).invoke(coll3, "abcde");//绕过编译器来插入数据


ArrayList<E>类定义和ArrayList<Integer>类引用中设计如下术语:
*整个成为ArrayList<E>泛型类型
*ArrayList<E>的E成为类型变量或者类型参数
*整个ArrayList<Integer>成为参数化的类型
*ArrayList<Integer>称为参数化的类型
*ArrayList<Integer>中的Integer称为类型参数的实例或者实例类型参数
*ArrayList<Integer> 中的<>念着typeof
*ArrayList称为原始类型

 

参数化类型与袁术类型的兼容性:
*参数化类型可以引用一个原始类型的对象,编译报告警告,例如:
Colection<String> c = new Vector();
*原始类型可以引用一个参数化类型的对象,编译报告警告,例如:
Collection c = new Vector<String>();

参数化类型不考虑类型参数的继承关系:
* Vector<String> v = new Vector<Objcet>();//错误!
* Vector<Object> v = new Vector<String>();//也错误


泛型中的?通配符:
Collection<?>其中的?是可以兼容所有数据类型格式。但是调用后就无法使用跟参数有关的方法。例如add,remove

总结:
使用?通配符可以引用其他各种参数化的类型,?通配符定义的变量主要用作引用,可以调用与参数无
关的方法,不能调用与参数有关的方法。
-------------------------------------------------------------------------------------------

泛型中的?通配符的扩展

*限定通配符的上边界:
正确:Vector<? extends Number> x = new Vector<Integer>();
错误:Vector<?extends Number> x = new Vector<String>();
*限定通配符的下边界:
正确:Vector<? super Integer> x = new Vector<Number>();
错误:Vector<? super Integer> x = new Vector(Byte)();

提示:
限定通配符总是包括自己。


--------------------------------------------------------------------------------------
泛型的综合安案例

遍历所有KEY值和VALUE

HashMap<String,Integer> maps  = new HashMap<String, Integer>();
  maps.put("老大", 58);
  maps.put("老二", 49);
  maps.put("老三", 35);
  maps.put("老四", 27);
  Set<Map.Entry<String, Integer>> entryset = maps.entrySet();
  for(Map.Entry<String, Integer> map : entryset){
   String all = map.getKey().out.println(all);
  }

--------------------------------------------------------------------------------------

泛型方法的练习题
--编写一个泛型方法,自动将Object类型的对象转换成其他类型。
 
      // 强制将Object对象转换成相应的类型
 private static <T>T changeType(Object obj){
  return (T)obj;
 }

--定义一个方法,可以将任意类型的数组中的所有元素填充为相应的类型的某个对象。
 在这种情况下,前面的通配符方法要比泛型方法更有效,当一个类型变量用来表达两个参数之间或者
参数和返回值之间的关系时,即同一个类型变量在方法签名的两处被使用,或者类型变量在方法体代码中也被使用而不是仅在签名的时候使用,才需要使用泛型方法。
main{
  String s1  = changeType(obj);
  copy1(new Vector<Date>(),new Date[10]); //因为Vector本身就是集合所以T就是Date,并且方法中调用的是一个对象,所以copy1方法中的两个参数类型也必须一致。
}

public static <T> void copy1(Collection<T> desc,T[] src){
  
 }
--采用自定义泛型方法的方式打印出任意参数化类型的集合中的所有内容。
--定义一个方法,把任意参数类型的集合中的数据安全的复制到相应类型的数组中。
--定义一个方法,把任意参数类型的一个数组中的数据安全的复制到相应类型的另一个数组中
-------------------------------------------------------------------------------------------
由c++的末班函数引入自定义泛型
-> 如下函数的结构很相似,仅仅类型不同:
* int add(int x,int y ){
return x+y;
}
* float add(float x,float y ){
return x+y;
}
* double add(double x,double y ){
return x+y;
}


c++ 用模板函数解决,只写一个通用的方法,它可以使用各种类型,示意代码如下
template<class T>
T add(T x,T y){
return(T)(x+y);
}

1.JAVA中的泛型类型(或者泛型)类似于 c++中的模板。但是这种相似性仅限于表面。JAVA语言中的泛型基本上完全是在编译器中实现,用于编译器执行类型检查和类型判断,然后生成普通

的非泛型的字节码,这种实现技术称为擦除(erasure) (编译器使用泛型类型信息保证类型安全,然后再生成字节码之前将其清除).
这是因为扩展虚拟机指令集来支持泛型被认为是无法接受的,这会为java 厂商升级其JVM造成难以逾越的障碍。所以java的泛型采用了可以完全在编译器中实现的擦出方法。

4.这个需要使用泛型方法进行定义,如果使用如下形式:
static void copy(Collection a,Object[] b);
否则有可能出现 A 类型的数据复制进B类型的数组中的情况。
使用泛型方法定义形式为:
static<T> void copy(Collection<T> a,T[]b);

 

除了在应用泛型时可以使用extends限定符,在定义泛型时也可以使用extends限定符,例如Class.getAnnotation()方法的定义。并且可以用&类指定多个边界,如<V extends Serializable &

cloneable> void method(){}

交换数组中的两个元素的位置的泛型方法语法定义如下:
main{
int[] inx = new int[]{1,2,3,4,5}; //如果将int格式放入方法中则错误,因为泛型的实际类型只能是对象,只能是引用类型,不能是基本类型。

String[] str = new String[]{"aa","bb","cc","dd"};
change(str,1,2);
}

 

public static <T> void change(T[] index,int i ,int j){
  T tmp = index[i];
  index[i ] = index[j];
  index[j] = tmp;
  
 }


------------------------------------------------------------------------------------------
定义泛型类型
如果类的实例对象中的多处都要用到同一个泛型参数,及这个地方引用的泛型类型要保持同一个实例类型时,这个时候就要采用泛型类型的方式进行定义,也就是类级别的泛型,语法格式如

下:
public class GenericDao<E>{
   private E filed1;
 public void save(E obj){}
 public E getByid(int id){};
}

------------------------------------------------------------------------------------------

通过反射获得泛型的参数化类型
*高难度知识点
Vector<Date> v1= new Vector<Date>();//无法从v1得到Vector集合中的类型,因为它与无规定类型返
回的字节码是相同的。但是我们可以定义一个方法来接收,然后通过方法可以得到返回值类型的列表;
public static void applyVector(Vector<Date> v1){

}

main{

  Method method = GenericTest.class.getMethod("applyVector", Vector.class);//得到方法和参数类型
  Type[] types  = method.getGenericParameterTypes();//得到所有的参数类型
  //Parameterized参数化类型
  ParameterizedType parame = (ParameterizedType)types[0]; //因为只定义了一个,所以只找到0个就可以了
  System.out.println(parame.getRawType()); //得到原始类型Vector
  //得到实际类型参数,返回是多个,需要指定某个类型参数,因为我们知道只有一个所以定义0个就可以
  System.out.println(parame.getActualTypeArguments()[0]);
}

此知识点比较复杂,不可用简单的变量名就求到集合泛型中的参数类型。以上是原理。

原创粉丝点击