首页 > 技术文章 > 什么是泛型

hph1728390 2019-06-11 19:27 原文

什么是泛型为什么要使用泛型

泛型就是参数化类型

泛型的作用

减少重复代码

像dao接口中存在样式雷同的代码:
EmpDao:
package com.aaa.gen.dao;
import com.aaa.gen.entity.Emp;
import java.util.List;
/**
* 员工管理dao接口
DetpDao:
*/
public interface EmpDao {
/**
* 查询所有的员工信息
* @return
*/
public List<Emp> listAll();
/**
* 保存员工信息
* @param emp
* @return
*/
public int save(Emp emp);
/**
* 删除员工信息
* @param emp
* @return
*/
public int delete(Emp emp);
/**
* 修改员工信息
* @param emp
* @return
*/
public int update(Emp emp);
/**
* 根据主键查询 员工的信息
* @param id
* @return
*/
public Emp find(Long id);
}
package com.aaa.gen.dao;
import com.aaa.gen.entity.Dept;
import java.util.List;
/**
* 部门管理dao接口
*/
public interface DeptDao {
/**
有这么 多重复代码,肯定是不好的,我们应该使用一种范式提取出来。我们可以定义一个公共的BaseDao接口来
解决这种问题:
* 查询所有的部门信息
* @return
*/
public List<Dept> listAll();
/**
* 保存部门信息
* @param dept
* @return
*/
public int save(Dept dept);
/**
* 删除部门信息
* @param dept
* @return
*/
public int delete(Dept dept);
/**
* 修改部门信息
* @param dept
* @return
*/
public int update(Dept dept);
/**
* 根据主键查询 部门的信息
* @param id
* @return
*/
public Dept find(Long id);
}
package com.aaa.gen.common;
import com.aaa.gen.entity.Dept;
import java.util.List;
public interface BaseDao<T> {
/**
* 查询所有的实体信息
* @return
*/
public List<T> listAll();
然后针对某个特定多的接口比如EmpDao,我们可以让EmpDao继承BaseDao接口,同时指定泛型的类型:
帮助我们提前发现一些程序的错误
/**
* 保存实体信息
* @param t
* @return
*/
public int save(T t);
/**
* 删除实体信息
* @param t
* @return
*/
public int delete(T t);
/**
* 修改实体信息
* @param t
* @return
*/
public int update(T t);
/**
* 根据主键查询 实体的信息
* @param id
* @return
*/
public T find(Long id);
}
package com.aaa.gen.dao;
import com.aaa.gen.common.BaseDao;
import com.aaa.gen.entity.Emp;
import java.util.List;
/**
* 员工管理dao接口
*/
public interface EmpDao extends BaseDao<Emp> {
}

帮助我们提前发现一些程序的错误
package com.aaa.gen.test;
import java.util.ArrayList;
import java.util.List;定义泛型接口或者类
定义泛型接口
泛型接口在被实现的时候,如果实现类不再需要泛型,则需要指定泛型的具体类型:
/**
* 测试泛型
*/
public class Test01 {
/**
* 打印list中所有的内容
*/
public static void printList(List<String> list){
for(int i=0;i<list.size();i++){
String str = list.get(i);
System.out.println(str);
}
}
public static void main(String[] args) {
List<String> list = new ArrayList<String>();
list.add("Java");
list.add("C#");
list.add("python");
list.add(123);
Test01.printList(list);
}
}
package com.aaa.gen;
/**
* 定义泛型接口list
* 在接口后面使用<>表示,在<>可以定义泛型的形参,一般形参都使用单独的一个大写字母来表示
* 多个发型的形参用逗号进行间隔 经常用的泛型的标识有T E
*
*/
public interface List<T> {
/**
* 迭代元素
* @param t
*/
public void iterator(T t);
}如果实现类继续使用泛型,则可以不指定泛型的具体类型:
定义泛型类
package com.aaa.gen;
/**
* 如果实现类中不再使用泛型,则需要指定泛型的具体类型
*/
public class ArrayList implements List<String> {
@Override
public void iterator(String s) {
}
}
package com.aaa.gen;
/**
* 实现类中如果继续使用泛型 ,则不必指定泛型的具体类型
* @param <T>
*/
public class LinkedList<T> implements List<T>{
@Override
public void iterator(T t) {
}
}
package com.aaa.gen;
/**
* 泛型类
*/
public class Apple<T> {
//声明泛型变量info
private T info;
public T getInfo() {
return info;
}
public void setInfo(T info) {
this.info = info;
}
}在使用的时候:
泛型通配符
需求:定义一个类,类中需要有打印一个字符串集合中的所有元素的方法,还需要有打印一个整数集合中的所有元
素的方法
package com.aaa.gen.test;
import com.aaa.gen.Apple;
/**
* 测试泛型类
*/
public class Test02 {
public static void main(String[] args) {
Apple<String> apple= new Apple<String>()apple.setInfo("红色");
System.out.println(apple.getInfo());
Apple<Integer> apple2= new Apple<Integer>();
apple2.setInfo(10);
System.out.println(apple2.getInfo());
}
}
package com.aaa.gen.test;
import java.util.List;
public class Test03 {
/**
* 打印字符串集合中的所有的元素
* @param list
*/
public void printStr(List<String> list){
for(String str : list){
System.out.println(str);
}
}
/**
* 打印整数集合中的所有的元素
* @param list
*/
public void printInt(List<Integer> list){
for(Integer num :list){
System.out.println(num);
}
}我们发现所有打印的方法的代码结构上都是类似的,打印每种类型的变量的集合都需要再定义一个方法,这样做非
常麻烦,有没有一个通用的方法可以解决这个问题?
我们通过泛型通配符来解决这个问题,java提供一个方案,List 不是所有List<其他类型>的父类,但是List<?>可以
理解为所有List<其他类型>的父类:
/**
* 打印小数集合中的所有的元素
* @param list
*/
public void printDouble(List<Double> list){
for(Double num :list){
System.out.println(num);
}
}
}
package com.aaa.gen.test;
import java.util.ArrayList;
import java.util.List;
/**
* 使用List<Object>来代替List<String>List<Double> List<Integer>
*/
public class Test04 {
/**
* 打印所有的object对象
* @param list
*/
public void print(List<Object> list){
for(Object obj : list){
System.out.println(obj);
}
}
public static void main(String[] args) {
List<String> strList = new ArrayList<String>();
strList.add("java");
strList.add("c#");
//String 是Object的子类,但是List<String> 还是不是List<Object>的子类了?不是了
//我们还是希望List<Object>是List<String>或者是List<其他类型>的父类
new Test04().print(strList);
}
}泛型通配符上限
需求:声明一个方法,打印所有数字类型的集合中的元素
package com.aaa.gen.test;
import java.util.ArrayList;
import java.util.List;
/**
* 使用List<?>来代替List<Object>
*/
public class Test05 {
/**
* 打印所有的object对象
* @param list
*/
public static void print(List<?> list){
for(Object obj : list){
System.out.println(obj);
}
}
public static void main(String[] args) {
List<String> strList = new ArrayList<String>();
strList.add("java");
strList.add("c#");
//可以理解为List<?>是所有List<其他类型>的父类
new Test05().print(strList);
List<Integer> intList = new ArrayList<Integer>();
intList.add(1);
intList.add(2);
//可以理解为List<?>是所有List<其他类型>的父类
new Test05().print(intList);
}
}
package com.aaa.gen.test;
import java.util.ArrayList;
import java.util.List;
/**
* 泛型通配符上限
*/
public class Test06 {
/**
* 打印所有的数字类型集合中的元泛型方法
原先在使用泛型的时候,只把泛型定义在了类上或者接口上。泛型也可以只在一个方法上来使用。
举例:声明一个泛型方法 合并两个list集合中的元素
* @param list
*/
public void printNum(List<? extends Number> list){
for(Number n : list){
System.out.println(n);
}
}
public static void main(String[] args) {
List<Integer> inStrs = new ArrayList<Integer>();
inStrs.add(1);
inStrs.add(2);
//同List<Object>不是List<其他类型>的父类一样,List<Number>也不是List<Number的子类>的父类
//如果要解决这种问题,就需要用到泛型通配符上限
new Test06().printNum(inStrs);
List<Double> doStrs = new ArrayList<Double>();
doStrs.add(1D);
doStrs.add(2D);
new Test06().printNum(doStrs);
List<String> strs = new ArrayList<String>();
strs.add("abc");
strs.add("def");
new Test06().printNum(strs);
}
}
package com.aaa.gen.test;
import java.util.ArrayList;
import java.util.List;
/**
* 泛型方法
*/
public class Test07 {
/**
* 合并两个list集合
* @param a
* @param b
*/
/* public static void join(List<String> a , List<String> b){
for(String item :a){
b.add(item);
}
}*/问题,如果b中的泛型类型声明成Object会报错:
public static <T> void join(List<T> a , List<T> b){
for(T item :a){
b.add(item);
}
System.out.println(b);
}
public static void main(String[] args) {
List<String> a = new ArrayList<String>();
a.add("1");
a.add("2");
List<String> b = new ArrayList<String>();
b.add("3");
Test07.join(a,b);
List<Integer> a1 = new ArrayList<Integer>();
a1.add(1);
a1.add(2);
List<Integer> b1 = new ArrayList<Integer>();
b1.add(3);
Test07.join(a1,b1);
}
}怎么在不把Object改成String的前提下解决这种问题?泛型通配符下限
需求:要返回最后一个添加的元素
怎么样修改方法才能让返回值变成添加元素时的类型?
package com.aaa.gen.test;
import java.util.ArrayList;
import java.util.List;
/**
* 泛型方法 发型通配符下限
*/
public class Test08 {
/**
* 合并两个list集合 返回最后一个添加的元* @param a
* @param b
*/
/* public static void join(List<String> a , List<String> b){
for(String item :a){
b.add(item);
}
}*/
public static <T> T join(List<? extends T> a , List<T> b){
T last = null;
for(T item :a){
last = item;
b.add(item);
}
System.out.println(b);
return last;
}
public static void main(String[] args) {
List<String> a = new ArrayList<String>();
a.add("1");
a.add("2");
a.add("3");
List<Object> b = new ArrayList<Object>()//返回值是什么类型,原先放置的时候类型是String类型,现在还能不能用String类型来接收返回值了?
Object last = Test08.join(a,b);
}
}
package com.aaa.gen.test;擦除
把一个具有泛型信息的变量赋值给一个没有泛型信息的变量,泛型的信息会消失,这就叫做擦除。
import java.util.ArrayList;
import java.util.List;
/**
* 泛型方法 发型通配符下限
*/
public class Test08 {
/**
* 合并两个list集合 返回最后一个添加的元* @param a
* @param b
*/
/* public static void join(List<String> a , List<String> b){
for(String item :a){
b.add(item);
}
}*/
public static <T> T join(List<T> a , List<? super T> b){
T last = null;
for(T item :a){
last = item;
b.add(item);
}
System.out.println(b);
return last;
}
public static void main(String[] args) {
List<String> a = new ArrayList<String>();
a.add("1");
a.add("2");
a.add("3");
List<Object> b = new ArrayList<Object>()//返回值是什么类型,原先放置的时候类型是String类型,现在还能不能用String类型来接收返回值了?
// Object last = Test08.join(a,b);
//怎么样修改方法才能让返回值变成添加元素时的类型
String last = Test08.join(a,b);
}
}
package com.aaa.gen;
/**
* 泛型类
*/
public class Apple<T> {测试:
//声明泛型变量info
private T info;
public T getInfo() {
return info;
}
public void setInfo(T info) {
this.info = info;
}
}
package com.aaa.gen.test;
import com.aaa.gen.Apple;
/**
* 擦除
*/
public class Test09 {
public static void main(String[] args) {
Apple<String> a1 = new Apple<String>();
a1.setInfo("红色");
String info = a1.getInfo();
//把一个具有泛型信息的变量赋值给一个没有泛型信息的变量
Apple a2=a1;
//泛型类型信息会消失
Object info1 = a2.getInfo();
}
}

 

推荐阅读