学习日记-泛型

来源:互联网 发布:甘肃电大网络考试平台 编辑:程序博客网 时间:2024/05/18 02:23

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

泛型

在java学习的过程中我发现java的集合有一个缺点,那就是它不会记住你放进去的对象的数据类型,当再次需要取出该对象时该对象的编译类型就变成了Object类型。因此泛型就应运而生了。所谓泛型就是允许在定义类、接口、方法时适用类型参数,这个类型参数将在声明变量,创建对象,调用方法时动态的指定。

注意并不存在泛型类

public class R<T>
{
 // 下面代码错误,不能在静态Field声明中使用类型形参
// static T info;
 T age;
 public void foo(T msg){}
 // 下面代码错误,不能在静态方法声明中使用类型形参
// public static void bar(T msg){}
}

不管为泛型类型传入哪一种类型实际参数,对于java来说,他们依然被当成同一个类处理,在内存之中也只占一块存储空间,因此在静态方法,静态初始化块中都不允许使用类型形参。因此上边显示了这种状况。还有就是系统中并不会真正生成泛型类,所以instanceOf运算符之后不可以使用泛型类。

为了表示各种泛型的父类,我们就需要使用类型通配符(?)。但是虽然带通配符的集合表示各种泛型的父类,但是并不能将元素加入到其中例如:

List<?>c=new ArrayList<String>();

//此处会引发编译错误

c.add(new Object());

设定类型通配符的上限例如:

public class Canvas(){

//在同一块画布上绘制不同的多个形状,使用受限制的通配符

public void drawAll(List<? extends Shap>shaps){

for(Shap s:shaps){

s.draw(this);

}

}

}

java中泛型不允许使用通配符形参时设定上限,而且可以在定义类型形参时设定上限,用于表示传给该类型形参的实际类型要么是该上限类型,要么是该上限类型的子类。

例如设定类型形参的上限:

public class Apple<T extends Number>
{
 T col;
 public static void main(String[] args)
 {
  Apple<Integer> ai = new Apple<>();
  Apple<Double> ad = new Apple<>();
  // 下面代码将引起编译异常,下面代码试图把String类型传给T形参
  // 但String不是Number的子类型,所以引发编译错误
  Apple<String> as = new Apple<>();  //①
 }
}

 

设定类型通配符的下限

public class MyUtils
{
 // 下面dest集合元素类型必须与src集合元素类型相同,或是其父类
 public static <T> T copy(Collection<? super T> dest
  , Collection<T> src)
 {
  T last = null;
  for (T ele  : src)
  {
   last = ele;
   dest.add(ele);
  }
  return last;
 }
 public static void main(String[] args)
 {
  List<Number> ln = new ArrayList<>();
  List<Integer> li = new ArrayList<>();
  li.add(5);
  // 此处可准确的知道最后一个被复制的元素是Integer类型
  // 与src集合元素的类型相同
  Integer last = copy(ln , li);    
  System.out.println(ln);
 }
}

在上边不论src结合类型是什么,只要dest集合元素的类型与前者相同或是其父类即可。

java中正式因为有了泛型才使得可以在编译的时候检查类型安全,并且所有的强制转换都是自动和隐式的,提高了代码的重用率。

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