什么时java泛型?
泛型时jdk1.5版本以后出现的一种对类、方法、接口的一种类型的约束,这种类型的约束是存在与编译时期的一种约束,在程序的运行时期是没有泛型的运用。
泛型的作用只存在与代码的编译时期,运行时没有泛型的存在
泛型即"参数化类型"
就是将对象将参数传递,为了能够更好的理解泛型,我们以上一篇中的分页工具类来解释,代码如下:
package com.zs.util; import com.zs.entity.User; import java.util.List; public class PageUtil { private int firstPage; private int proPage; private int currentPage; private int nextPage; private int lastPage; private List<User> list; public PageUtil() { } public PageUtil(int currentPage,int countPage, List<User> list) { this.firstPage = 1; this.currentPage = currentPage; this.lastPage = countPage; this.proPage = this.currentPage == 1 ? 1 : (this.currentPage - 1); this.nextPage = this.currentPage == this.lastPage ? this.currentPage : this.currentPage + 1; this.list = list; } public int getFirstPage() { return firstPage; } public void setFirstPage(int firstPage) { this.firstPage = firstPage; } public int getProPage() { return proPage; } public void setProPage(int proPage) { this.proPage = proPage; } public int getCurrentPage() { return currentPage; } public void setCurrentPage(int currentPage) { this.currentPage = currentPage; } public int getNextPage() { return nextPage; } public void setNextPage(int nextPage) { this.nextPage = nextPage; } public int getLastPage() { return lastPage; } public void setLastPage(int lastPage) { this.lastPage = lastPage; } public List<User> getList() { return list; } public void setList(List<User> list) { this.list = list; } }View Code
这是上一篇中我们写的分页栏的工具,当我们在前台点击了下一页等跳转按钮后,就会发送一个页数的请求到后台,后台将传递过来的页数作为当前页,然后获取当前页的数据信息,并存入一个集合中,然后通过分页类的构造方法计算上一页,下一页等信息,并将当前页的信息一并存入工具类里了。
上一篇里例子中,我们只创建了一个用户的类,只读取了user表的数据,那么如果现在有一个person表,我们要获取person表的内容,在一系列操作后获取了当前页的内容,我们要存入List<Person>类型的list中,但是我们的分页类PageUtil内的list是一个List<User> 类型的,这样就出现了类型的不一致,但是分页的代码都是一样的,我们不能因为这个小原因,重新创建类,因此我们就会想,我们能不能将这个List内的类型当作参数传递过去呢,我们调用方法时,写的是什么类型,那么类内部的List就是什么类型。
这种将对象作为参数传递的行为就是泛型。
还是前面的pageUtil类,在没有用泛型时,现在只能传递User为类型的list,那么我们将它进行改造成泛型。
package com.zs.util; import java.util.List; public class PageUtil<T> { private int firstPage; private int proPage; private int currentPage; private int nextPage; private int lastPage; private List<T> list; public PageUtil() { } public PageUtil(int currentPage,int countPage, List<T> list) { this.firstPage = 1; this.currentPage = currentPage; this.lastPage = countPage; this.proPage = this.currentPage == 1 ? 1 : (this.currentPage - 1); this.nextPage = this.currentPage == this.lastPage ? this.currentPage : this.currentPage + 1; this.list = list; } public int getFirstPage() { return firstPage; } public void setFirstPage(int firstPage) { this.firstPage = firstPage; } public int getProPage() { return proPage; } public void setProPage(int proPage) { this.proPage = proPage; } public int getCurrentPage() { return currentPage; } public void setCurrentPage(int currentPage) { this.currentPage = currentPage; } public int getNextPage() { return nextPage; } public void setNextPage(int nextPage) { this.nextPage = nextPage; } public int getLastPage() { return lastPage; } public void setLastPage(int lastPage) { this.lastPage = lastPage; } public List<T> getList() { return list; } public void setList(List<T> list) { this.list = list; } }View Code
现在这个工具类,就可以保存各种类型的数据集合了,我们可以创建多个类型来测试看能不能放进去。这里因为还要写泛型的应用,就不做测试了。
泛型的应用:
1.泛型类
package com.zs.service; /** * 泛型的类型类似于object类,什么类型都可以,但是不可以使用八大基本类型int、double..., * 如果使用八大基本类型的数据,要使用包装类Integer、Double... * 泛型定义在类上public class 类名<泛型类型1,..>可以定义多个泛型类型 * @param <E> */ public class Demo1<E> { private E e; public E getE() { return e; } public void setE(E e) { this.e = e; } }
这样就创建了一个简单的泛型类。e可以是任意类型,还可以传递多个类型:
package com.zs.service; import java.util.ArrayList; import java.util.HashMap; import java.util.List; /** * 泛型的类型:T:type E:element K:key V:value这些都指代类型,没有区别 * @param <E> * @param <K> * @param <Y> */ public class Demo2<E,K,Y> { private List<E> e; private HashMap<K,Y> map; public List<E> getE() { return e; } public void setE(List<E> e) { this.e = e; } public HashMap<K, Y> getMap() { return map; } public void setMap(HashMap<K, Y> map) { this.map = map; } }
可以看出,在创建demo的对象是,声明了list的类型为string类型,因此list只能放string类型,如果存放integer类型会报错,同样的demo2里的hashmap的数据类型为string,integer
在创建对象时,会根据实力化对象时的类型,自动填充内部的E,K,V等,按照顺序填充。
2.泛型方法
package com.zs.service; public class Demo3 { /** * 泛型方法的参数类型可以是任意类型的,但是在声明方法时,要在返回值前声明这是个泛型方法<T> * @param t * @param <T> */ public <T> void fun1(T t) { System.out.println("方法执行了" + t); } public static void main(String[] args) { Demo3 demo3 = new Demo3(); demo3.fun1("字符串"); demo3.fun1(111); demo3.fun1(true); /** * 运行结果,可以看到fun内可以传任意类型参数 */ } }
3.泛型接口
package com.zs.service; /** * 如果一个类实现了泛型接口,那么这个类必须得到泛型 * @param <T> */ public class Demo4Impl<T> implements Demo4<T> { @Override public void fun(T t) { System.out.println("执行了" + t); } public static void main(String[] args) { Demo4<String> demo4 = new Demo4Impl<>(); /*上面声明了泛型类型为string类型,因此fun只能传string类型参数*/ demo4.fun("111"); } }
泛型的作用:
1.提高了程序的安全性(泛型在集合里的使用)
2.将运行期遇到的问题,提前到了编译期
3.省去了代码强转的麻烦
4.提高了代码的重用性,实现代码的公共的封装
泛型的高级应用:
1.泛型通配符<?>
2.<? extends E>
向下限定,E及其子类
3.<? supper E>
向上限定,E及其父类
举例说明:
package com.zs.service; import java.util.List; public class Demo5 { /** * 通配符类型传参,相当于object,可以传任意类型 * @param list */ public void fun1(List<?> list) { System.out.println(list); } /** * list的类型可以是demo3或其所有子类类型的 * @param list */ public void fun2(List<? extends Demo3> list) { System.out.println(list); } /** * list的类型可以是demo3或其父类类型的 * @param list */ public void fun3(List<? super Demo3> list) { System.out.println(list); } }