黑马程序员--泛型

来源:互联网 发布:中医之钥 知乎 编辑:程序博客网 时间:2024/04/30 18:41

http://edu.csdn.net/heima android培训http://edu.csdn.net/heima ; java培训期待与您交流!

泛型

一、泛型的概述。

1、泛型的由来:jdk1.5版本出现的技术,是一种安全机制。泛型其实就是通过<>定义了一个形式参数,专门用来接收实际参数。
泛型用的最多的就是集合,集合中可以存储任意类型对象,但是用其特有方法时,需要向下转型,但是当存储的对象是不同时,会出现问题。所以要加泛型明确类型。

2、集合容器中使用泛型解决了哪些问题?

在存储元素时,就不允许存储不同类型的元素,存储了就编译失败。

如果存储的对象类型不一致,在转型过程中就会出现ClassCastException异常。

3、泛型好处:
 a、将运行时期的ClassCastException异常转移到编译时期,进行检查。
 b、避免了向下转型的麻烦。转型自动完成。
4、什么时候写泛型呢?
 api文档描述的类和接口中带有<>就需要在使用时,定义泛型。
5、泛型的擦除和补偿。
 泛型的擦除:泛型技术是用于编译时期的技术,编译器会按照<>中的指定类型元素进行检   查,检查通过后,产生的class文件中是没有泛型的,这就是泛型的擦除。
 泛型的补偿:运行时, 可以根据具体的元素对象获取其具体类型,并用该类型对元素进行自动转换。
6、泛型可以定义在哪里?

 泛型可以定义在类上,可以定义在方法上,也可以定义在接口上。

7、泛型通配符:?
      当操作的不同容器中的类型都不确定的时候,而且使用的都是元素从Object类中继承的方法。表示可以匹配任意类型。
      这是泛型就用通配符?来表示即可。
8、泛型的限定:

     上限:? extends E
         什么时候使用上限一般情况下,只要往容器中添加元素时,使用上限。?extends E
      下限:? super E

提示:在反射中也用到了泛型。
二、代码演示。
自定义泛型:模拟泛型类,比较带泛型和不带泛型的区别。
定义一个工具类,这个工具类可以对所有对象进行(设置,获取)功能。   

   


publicclass GenericClass {

    publicstaticvoid main(String[] args) {

       Tool t = new Tool();//创建不带泛型的工具类。

       t.setObject(new Student());

       Worker w = (Worker)t.getObject();//需要强转,运行时才出现错误。

       Util<Worker> u = new Util<Worker>();//创建带泛型的工具类。

       u.setObject(new Worker());

       Worker w2 = u.getObject();//因为带泛型,所以不需要强转。

    }

}

//定义学生类。

class Student{

}

class Worker{ 

}

//定义一个工具类可以对任意对象进行(设置和获取)。

class Tool{

    private Objectobj;

    publicvoid setObject(Object obj){

       this.obj = obj;

    }

    public Object getObject(){

       returnobj;

    }

}

//定义带泛型的工具类,可以对任意对象进行设置和获取。

class Util<E>{//在类上定义泛型。

    private Ee;

    publicvoid setObject(E e){

       this.e = e;

    }

    public E getObject(){

       returne;

    }

}

 

 

自定义泛型:泛型定义在方法上:
publicclass
GenericMethod {

    publicstaticvoid main(String[] args) {

       Tool2<String> t = new Tool2<String>();

       t.show("abc");//参数只能是字符串。

       t.myPrint(new Integer(4));//泛型定义在方法上,不跟着类的泛型走,参数可以是任意类型的。

       t.method(new Long(83));//静态方法,想要使用泛型,只能定义在方法上。

    }

}

class Tool2<E>{

    //这样方法上的泛型就跟着类走。

    publicvoid show(E e){

       System.out.println("show:"+e.toString());

    }

    //这个方法中参数可以是任意的,不跟着类上的泛型走,参数可以是任意类型的。

    public <A>void myPrint(A a){

       System.out.println("myPrint:"+a.toString());

    }

    //注意:静态方法不能访问类上定义的泛型,如果需要泛型只能定义在方法上。

    publicstatic <Y>void method(Y y){

       System.out.println("static method:"+y.toString());

    }

}

自定义泛型:模拟泛型接口:
publicclass
GenericPort {

    publicstaticvoid main(String[] args) {

       new InterImpl().show("abc");//类实现接口时,就明确了是Stirng类型。

       new InterImpl2<Integer>().show(new Integer(5));//在创建对象时,才明确具体类型。

    }

}

interface Inter<V>{

    publicabstractvoid show(V v);

}

//实现接口,明确具体类型。

class InterImplimplements Inter<String>{

    publicvoid show(String s) {

       System.out.println("show:"+s);

    }

}

//实现接口,也不明确具体类型。

class InterImpl2<C>implements Inter<C>{

    publicvoid show(C c) {

       System.out.println("show:"+c);

    }

}
//实现接口,也不明确具体类型。
class InterImpl2<C> implements Inter<C>{
 public void show(C c) {
  System.out.println("show:"+c);
 }
}

 

通配符的演示?

    当操作的不同容器中的类型都不确定的时候,而且使用的方法都是从Object类中继承的方法。这时可以用通配符来表示。?相当于用Object来接收任意对象的引用。

publicclass GenericAdvDemo {

    publicstaticvoid main(String[] args) {

       ArrayList<String> al1 = new ArrayList<String>();

       al1.add("java1");

       al1.add("java2");

       al1.add("java3");

      

       ArrayList<Integer> al2 = new ArrayList<Integer>();

       al2.add(4);

       al2.add(5);

       al2.add(9);

    }

    //定义一个用于迭代ArrayList集合的方法。

    publicstaticvoid printAl(ArrayList<?> al){

       Iterator<?> it = al.iterator();// ?通配符,相当于没写。

       while(it.hasNext()){

           System.out.println(it.next());

       }

    }

}

通配符的演示?

 当操作的不同容器中的类型都不确定的时候,而且使用的方法都是从Object类中继承的方法。
 这时可以用通配符来表示。?相当于用Object来接收任意对象的引用。

public class GenericAdvDemo {
 public static void main(String[] args) {
  ArrayList<String> al1 = new ArrayList<String>();
  al1.add("java1");
  al1.add("java2");
  al1.add("java3");
  
  ArrayList<Integer> al2 = new ArrayList<Integer>();
  al2.add(4);
  al2.add(5);
  al2.add(9);
 }
 //定义一个用于迭代ArrayList集合的方法。
 public static void printAl(ArrayList<?> al){
  Iterator<?> it = al.iterator();
  while(it.hasNext()){
   System.out.println(it.next());
  }
 }
}


通过模拟Collection中的boolean containsAll(Collection<?>);方法来说明通配符?的应用。

用泛型来模拟containsAll方法。
interaface Collection<E>{
    public boolean add(E e);
    public boolean containsAll(Collection<E> coll);//<E>来模拟。
}
用?通配符来模拟containsAll方法。注意跟用泛型模拟containsAll方法有什么不同。
interaface Collection<E>{
    public boolean add(E e);
    public boolean containsAll(Collection<?> coll);//用通配<>来模拟。
}

 

Collection c1<Integer> = new ArrayList<String>();
c1.add("abc1");
c1.add("abc2");
Collection<Integer> c2 = new ArrayList<String>();
c2.add("abc1");
Collection<Integer> c3 = new ArrayList<Integer>();


c1.containsAll(c2);//比较的容器存储的元素是同一类型的。
c1.containsAll(c3);//注意:containsAll方法使用的内部原理是通过继承Object中的equals进行判断相同,而equals(Object)方法是的参数类型是Object,说明任意类型都能接收。

意味着:"abc".equals(new Integer(5));也能比较。

总结:使用?通配符类模拟containAll,那么contaisAll()中的参数容器中元素可以是任意类型的,而使用E泛型来模拟,方法参数容器中元素类型只能是跟该容器同一类型的,所以使用?通配符跟适合描述containAll方法

 

张孝祥老师:泛型。

如何跳过泛型来存储元素?

1、  可以通过反射,获取class字节码,class中字节码中是没有泛型的(泛型的擦除),通过反射来调用add()方法存储元素就可以了。

2、  可以通过参数化类型与原始化兼容来实现。

参数化类型与原始化类型的兼容性:都互相兼容。

    Collection<String> coll = new ArrayList(); //可以兼容.

    Collection coll = new ArrayList(); //可以兼容。

    Collection coll<Object> = new ArrayList<String>();//不可以

    Collection coll<?> = new ArrayList<String>();//可以。


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

 

泛型练习题:

演示:演示通配符?的使用,定义一个方法,这个方法能接收任意集合,并将集合打印。

练习:定义一个方法用于交换数组中任意两个元素的位置,用泛型来完成。

练习:编写一个方法,自动将Object类型的对象转成其他类型。

练习:定义一个方法,可以将任意类型的数组中的所有元素填充为相应类型的某个对象。

练习:采用自定义泛型方法的方式打印出任意参数化类型的集合中的所有内容。

练习:定义一个方法,把任意参数类型的集合中的数据安全的复制到相应类型的数组中。

练习:定义一个方法,把任意参数类型中的一个数组中的数据安全的复制到相应类型的另一个数组中。

 

http://edu.csdn.net/heima android培训http://edu.csdn.net/heima ; java培训期待与您交流!详细请查看http://edu.csdn.net/heima

原创粉丝点击