关闭

黑马程序员——泛型-整理笔记

标签: java泛型黑马程序员
117人阅读 评论(0) 收藏 举报

                               ------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------

一、泛型概念

    泛型(Generic type 或者generics)是对 Java 语言的类型系统的一种扩展,以支持创建可以按类型进行参数化的类。可以把类型参数看作是使用参数化类型时指定的类型的一个占位符,就像方法的形式参数是运行时传递的值的占位符一样。

    限制泛型的可用类型
  由于没有限制class GenericsFoo<T>类型持有者T的范围,实际上这里的限定类型相当于Object,这和“Object泛型”实质是一样的。限制比如我们要限制T为集合接口类型。只需要这么做:
  class GenericsFoo<T extends Collection>,这样类中的泛型T只能是Collection接口的实现类,传入非Collection接口编译会出错。
  注意:<T extends Collection>这里的限定使用关键字 extends,后面可以是类也可以是接口。但这里的extends已经不是继承的含义了,应该理解为T类型是实现Collection接口的类型,或者T是继承了XX类的类型。

    下面我们根据一个例子来理解泛型:

import java.util.ArrayList;
import java.util.List;

 public class Test {
 
     public static void main(String[] args) {
         List list = new ArrayList();
         list.add("qqyumidi");
         list.add("corn");
        list.add(100);

        for (int i = 0; i < list.size(); i++) {
             String name = (String) list.get(i); // 1
             System.out.println("name:" + name);
         }
   }
 }

在如上的编码过程中,我们发现主要存在两个问题:

   1.当我们将一个对象放入集合中,集合不会记住此对象的类型,当再次从集合中取出此对象时,改对象的编译类型变成了Object类型,但其运行时类型任然为其本身类型。

   2.因此,//1处取出集合元素时需要人为的强制类型转化到具体的目标类型,且很容易出现“java.lang.ClassCastException”异常。

将上面的例子改为采用泛型来定义List

import java.util.ArrayList;
import java.util.List;

public class <span style="font-family:SimSun;">Tes</span>t {

	public static void main(String[] args) {
		List<String> list = new ArrayList<String>();
		list.add("qqyumidi");
		list.add("corn");

		for (int i = 0; i < list.size(); i++) {
			String name = (String) list.get(i); // 1
			System.out.println("name:" + name);
		}
	}
}

   采用泛型写法后,在//1处想加入一个Integer类型的对象时会出现编译错误,通过List<String>,直接限定了list集合中只能含有String类型的元素,从而在//2处无须进行强制类型转换,因为此时,集合能够记住元素的类型信息,编译器已经能够确认它是String类型了。

二、泛型的好处

     ①把运行时的异常转到了编译时期。

     ②避免了程序员强制类型的转换。

    什么时候定义泛型

     当我们定义方法的时候,由于不知道调用者会传入什么样的参数,这时候我们就可以定义泛型,但是当调用者在使用方法的时候,肯定知道自己需要传入什么样类型的参数,所以当调用者调用的时候,就要传入具体的引用数据类型。(不传入泛型的时候,那默认的类型就是Object)

      由于编译生成的字节码会去掉泛型的类型信息,只要能跳过编译器,就可以往某个泛型集合中加入其它类型的数据,例如,用反射得到集合,再调用其add方法即可。例如:

<span style="font-family:SimSun;">import java.util.ArrayList;

public class tt {

	public static void main(String[] args) throws Exception {

		ArrayList<Integer> list = new ArrayList<Integer>();
		list.add(12);
		list.getClass().getMethod("add", Object.class).invoke(list, "黑马程序员");
		System.out.println(list);

	}</span>
上述代码使用Java反射技术可以往泛型为Integer的ArrayList的对象中放入一个String对象。

三、类型通配符(?)

  泛型的通配符: ?就是通配符

     当我们定义类,方法(参数)不确定的时候,可以用?来表示。例如:

        public void getId(<?> e){}

    由于在方法中,传入的数据类型不确定,所以用到了泛型,但是在调用的时候,调用者肯定知道。如:

        int i = 98;

        getId(i);

        String s ="98";

        getId(s);

泛型就是要限制传递参数类型的,但是又可以接收任意的类型。

   为了表示各种泛型的父类,Java使用"?"来表示泛型通配.即List<?>来表示各种泛型List的父类.带这种通配符List泛型不能设置(set)元素,只能获取(get)元素。因为程序无法确定List中的类型,所以不能添加对象。但获取的对象肯定是Object类型。

例如下面的代码编译时就会出错

             List<?> list = new ArrayList<>();
             list.add(new Object());

泛型的限定

  限定通配符的上边界:

       正确:List<? extends Number> v = new List<Integer>();

       错误:List<? extends Number>v = new List<String>();

  限定通配符的下边界:

       正确:List<? super Integer>v =new List<Number>();

        错误:List<? super Integer>v =new List<Byte>();

   注意:限定通配符总是包括自己。

   泛型上限

      <? extends Collection>这被我们称之为上限,因为只能作用到其最顶层(父类),

     通过这样的定义,可以把其子类当做参数来传递,这主要使用在添加的。 因为在取出的时候方便,不用再进行类型的判断。

   泛型下限

     <? super Comparable> 这就是下限,通常用来进行比较。

    比较的时候既可以使用自己的比较器,也可以使用父类的比较器。


  







                               ------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:1557次
    • 积分:111
    • 等级:
    • 排名:千里之外
    • 原创:10篇
    • 转载:0篇
    • 译文:0篇
    • 评论:0条
    文章存档