黑马程序员--java高新技术----泛型

---------------------- ASP.Net+Android+IOS开发.Net培训、期待与您交流! ----------------------


jdk1.5加入了泛型这一概念。

泛型:用于解决安全问题,是一个安全机制。

好处:

        1.把原本的运行时会出现的类型转换异常(ClassCastException),转移到程序编译时期,方便程序员解决问题,让运行时期的问题减少,提高程序的安全性。

        2.避免了强制类型转换的麻烦。

        3.实现模板设计模式

通过一个例子了解泛型:




这个程序中向集合中添加数据,前三个添加的是字符串,最后一个添加的是整数。

编译时并不会出现问题,但是运行时会出现类型转换异常。



使用泛型:




使用泛型,把集合所存储的数据类型事先规定好。所以在程序中如果有其他类型的数据,编译就不会通过。





不过在实验中我发现,现在的java版本已经会自动把整数转换为字符串,所以如果使用的jdk版本高的话,在集合中存入整数可能不会出现问题。

但是通过另一中途径一定可以发现问题。




在这个程序中我直接存了一个对象到集合中,编译也不会出错,不过运行时出现了类型转换异常(java.lang.ClassCastException)。


这样,使用泛型的好处就一目了然了。程序员不注意可能会在存放字符串的集合中存入整数,编译时可能不会出现问题,一位程序可以用了就完事了,但是运行时会出现问题。如果存数据的动作由用户完成,程序员没有提供数据类型这个问题,用户在使用是出现了问题,那就麻烦了。


通过上面的列子可以看到泛型的作用。

那么,java中什么时候使用泛型呢?

通常在集合框架中很常见,因为集合是存放对象的,不想数组那样,在定义一个数组时就把数组的长度,类型都定义好了,集合都没有定义,所以使用泛型可以规定集合存放的数据类型。


通过查看Collection接口的API文档可以发现:


接口 Collection<E>


方法摘要
boolean add(E e)
确保此 collection 包含指定的元素(可选操作)。

注意Collection后面的<E>就是使用泛型,而在add()方法中,参数也规定为(E e)。


到这里基本可以理解反省的使用方法了,拿集合来说:

<>是泛型的标志,<>里面的内容是要存入集合的数据的类型,把类型以参数的方式传递给集合类。


泛型在比较器中也用到。

java.util
接口 Comparator<T>

类型参数:
T - 此 Comparator 可以比较的对象类型
方法摘要
int compare(T o1, T o2)
比较用来排序的两个参数。

举个例子来看看 Comparator接口所使用到的泛型。

按照字符串的长度进行比较。



Comparator接口可以比较不同对象的同一属性,比如比较两个学生的年龄大小,但是不能比较一个学生的年龄和另一个学生的姓名的大小。

这也可以理解为什么Comparator接口要用到泛型。


自己也可以写泛型类,模仿集合接口使用泛型的方法即可。

泛型也称为模板或参数多肽,既是模板,就应该有模板的特性,下面通过自己我写的一个泛型类来体现泛型的模板特性。



通过程序可以看到,utils类为泛型类,在utils类中定义了show()方法,参数为T类型。

main()方法中既可以传递字符串参数给show()方法,也可以传递Integer参数给show()方法,这样就不用分别为字符串和整型参数写不同的show()方法,这就体现出了模板的特性。


而且当给泛型类传递了数据类型参数后,就规定了泛型类对象所能接受的参数类型,如果传递的参数类型为其他类型,则编译不会通过,而不用泛型,编译时可以通过的。




因为在确定了数据类型为String类型后,又传递了整型和Object类型的参数,所以编译不通过。

这就体现了泛型的安全性特点。


除了定义泛型类,还可以定义泛型方法,反省方法的操作性更灵活,因为定义泛型类的话,整个类里面的方法接收的参数类型都是一致的,而定义泛型方法,则方法可以接收不同类型的数据。


泛型方法的定义格式:

        public <T> void show(T  t)
{
System.out.println(t);
}

使用时给改方法传递任何类型的参数都可以。




那么,可以在泛型类中再定义泛型方法吗?

会出错吗?

哪个优先级更高?

猜是猜不出来的,试试就知道了。




定义泛型方法时,参数类型<T>应该放在返回类型符前面,修饰符后面。

public static <T> void show(T  t){ } ;


再看下面一个例子:

Student类继承Person类,把Person对象和Student对象分别存入集合中,然后调用泛型方法printAll()打印。






如果使用反省方法打印的话,那么任意类型的对象都可以打印。

而如果只想让继承Person类的对象才可以使用打印方法打印,那些非Person继承类的对象不能打印,能否实现呢?答案是能。


这就要用到泛型限定。

语法是这样的:


                              ArrayList<? extends Person>


?是通配符,参数不是单单一个了,而是一个继承语句。





当给泛型方法printAll()传递非Person()子类对象作为参数是,编译就会报错,就不能使用该泛型方法。


这就完成了泛型限定,只有Person子类的对象才可以使用此泛型方法。


反省最重要的两个特点:

1. 安全

2. 模板


记住这两个特点,再去学习泛型就明白,所有泛型的使用都是为了实现这两个特性。




---------------------- ASP.Net+Android+IOS开发.Net培训、期待与您交流! ----------------------

   详细请查看 www.itheima.com


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章