一.泛型简介
- 把类型参数化,也就是将操作类型指定为一个参数,这种参数类型可以用在类,接口和方法的创建中,分别称为泛型类,泛型接口,泛型方法
二.代码实例
- 测试:在未规定类型的List里面add了String和Integer两种类型
package com.wfzn.iot.utils; import java.util.ArrayList; import java.util.List; public class CommTest { public static void main(String[] args) { List list = new ArrayList<>(); list.add("CSDN"); list.add("朱勇豪"); list.add(29); for (int i = 0; i < list.size(); i++) { String str = (String) list.get(i); System.out.println("泛型测试,str = " + str); } } } 结果: Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String 泛型测试,str = CSDN at com.wfzn.iot.utils.CommTest.main(CommTest.java:14) 泛型测试,str = 朱勇豪 Process finished with exit code 1
此时运行出错,类型不匹配,所以这时加上List,规定允许加入的类型,直接编译不通过,这就是泛型的优点之一,保证安全
三.优缺点
(1) 类型安全
使得类型错误在编译期间就被发现
(2) 消除强制类型转换
(3) 更高的效率
避免了拆箱和装箱
(4) 潜在的性能收益
四.常见泛型中字母的含义: 类<字母>
- T 代表类型
- K V 分别代表键值对中的key value
- E 代表Element
- ?表示不确定的类型
五.注意事项
- 定义一个泛型类时在<>中定义形式类型参数 例如:class A<K,V> 其中的K,V代表类型
- 实例化泛型对象是一定要指定类型,前后都要(其实后面不指定就是默认和前面一致) Generic genericInteger = new Generic(123456);
- 泛型必须为引用数据类型,不能为基本数据类型
- 不可定义泛型数组
- static 方法中不可以用泛型,泛型变量也不可用static修饰
- 泛型只在编译器有效
package com.wfzn.iot.utils; import io.swagger.models.auth.In; import java.util.ArrayList; import java.util.List; public class CommTest { public static void main(String[] args) { List<String> listStr = new ArrayList<String>(); List<Integer> listInt = new ArrayList<Integer>(); System.out.println(listInt.getClass()); System.out.println(listStr.getClass()); System.out.println(listStr.getClass().equals(listInt.getClass())); } } 结果 class java.util.ArrayList class java.util.ArrayList true Process finished with exit code 0
六、泛型的使用
(泛型类,泛型方法, 泛型接口)
- 泛型类
package com.wfzn.iot.utils; import lombok.Data; //此处T可以随便写为任意标识,常见的如T、E、K、V等形式的参数常用于表示泛型 //在实例化泛型类时,必须指定T的具体类型 public class Generic<T> { //key这个成员变量的类型为T,T的类型由外部指定 private T key; //泛型构造方法形参key的类型也为T,T的类型由外部指定 public Generic(T key){ this.key = key; } //泛型方法getKey的返回值类型为T,T的类型由外部指定 private T getKey(){ return key; } public static void main(String[] args) { //泛型的类型参数只能是类类型(包括自定义类),不能是简单类型 //传入的实参类型需与泛型的类型参数类型相同,即为Integer. Generic<Integer> genericInteger = new Generic<>(123456); //传入的实参类型需与泛型的类型参数类型相同,即为String. Generic<String> genericString = new Generic<>("朱勇豪"); System.out.println("泛型测试,key is "+genericInteger.getKey()); System.out.println("泛型测试,key is "+genericString.getKey()); //可以随便传 Generic generic = new Generic("111111"); Generic generic1 = new Generic(4444); Generic generic2 = new Generic(55.55); Generic generic3 = new Generic(false); System.out.println(generic.getKey()); System.out.println(generic1.getKey()); System.out.println(generic2.getKey()); System.out.println(generic3.getKey()); } } 结果 泛型测试,key is 123456 泛型测试,key is 朱勇豪 111111 4444 55.55 false Process finished with exit code 0
- 泛型接口
1.泛型接口 package com.wfzn.iot.utils; /** * @author Zhuyh * @date 2021-11-04 11:06 */ public interface Generator<T> { public T next(); } 2.未指定类型的实现类 package com.wfzn.iot.utils; public class GeneratorImpl<T> implements Generator<T> { @Override public T next() { return null; } } 3.指定参数的实现类 package com.wfzn.iot.utils; import java.util.Random; public class GeneratorParamImpl<T> implements Generator<String> { String[] strings = new String[]{"a", "bc", "defg"}; @Override public String next() { Random random = new Random(); System.out.print(strings[random.nextInt(3)]+" "); return strings[random.nextInt(3)]; } public static void main(String[] args) { final GeneratorParamImpl<String> stringGeneratorParam = new GeneratorParamImpl<>(); for (int i = 0; i < 100; i++) { stringGeneratorParam.next(); } } } 结果: a defg a bc bc bc defg bc bc defg
- 泛型通配符
情况
解决方式:通配符
package com.wfzn.iot.utils; public class Test { public static void main(String[] args) { final Generic<Integer> generic = new Generic<Integer>(123); final Generic<Number> generic2 = new Generic<Number>(123456); getValue(generic); getValue(generic2); } private static void getValue(Generic<?> generic){ System.out.println(generic.getKey()); } } 结果 123 123456
- 泛型方法
泛型类:是在实例化的时候指定类型
泛型方法:是在调用方法时指定类型
package com.wfzn.iot.utils; public class Test { public static void main(String[] args) { try { Object CSDN = genericMethod(Class.forName("com.wfzn.iot.utils.Generic")); System.out.println(CSDN); Object OSCHINA = genericMethod(Class.forName("com.wfzn.iot.utils.GeneratorImpl")); System.out.println(OSCHINA); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } } /** * 泛型方法的基本介绍 * @param tClass 传入的泛型实参 * @return T 返回值为T类型 * 说明: * 1)public 与 返回值中间<T>非常重要,可以理解为声明此方法为泛型方法。 * 2)只有声明了<T>的方法才是泛型方法,泛型类中的使用了泛型的成员方法并不是泛型方法。 * 3)<T>表明该方法将使用泛型类型T,此时才可以在方法中使用泛型类型T。 * 4)与泛型类的定义一样,此处T可以随便写为任意标识,常见的如T、E、K、V等形式的参数常用于表示泛型。 */ public static <T> T genericMethod(Class<T> tClass)throws InstantiationException,IllegalAccessException{ return tClass.newInstance(); } } 结果: 就是你 com.wfzn.iot.utils.Generic@707f7052 还是你 com.wfzn.iot.utils.GeneratorImpl@11028347 附加: Generic类 public class Generic<T> { public Generic(){} static { System.out.println("就是你,好像不是你"); } } GeneratorImpl类 public class GeneratorImpl<T> implements Generator<T> { public GeneratorImpl(){ } static { System.out.println("还是你"); } @Override public T next() { return null; } }
泛型方法与可变参数
package com.wfzn.iot.utils; public class Test { //静态方法中使用泛型,必须要将泛型定义在方法上。 public static <T> void printMsg(T...args){ for(T t:args){ System.out.println("泛型测试,it is "+t); } } public static void main(String[] args) { printMsg("1111",2222,"朱勇豪","0.00",55.55); } } 结果: 泛型测试,it is 1111 泛型测试,it is 2222 泛型测试,it is 朱勇豪 泛型测试,it is 0.00 泛型测试,it is 55.55
七、泛型上下边界
- 设定通配符上限
比如我现在想接受一个List集合它只能操作类型为【float,double,int等】,直接使用通配符是不行的
package com.wfzn.iot.utils; import java.util.ArrayList; import java.util.List; public class Test { public static void main(String[] args) { ArrayList<Integer> integers = new ArrayList<>(); ArrayList<Double> doubles = new ArrayList<>(); ArrayList<String> strings = new ArrayList<>(); test(doubles); test(integers); test1(doubles); test1(integers); //设置了list上限为Number时就不能存String test(strings); // test1(strings); } public static void test(List<?> list) { System.out.println(list.getClass()); } public static void test1(List<? extends Number> list) { System.out.println(list.getClass().getName()); } }
- 设定通配符下限(比较少见)
//传递进来的只能是Type或Type的父类 <? super Type>
八、泛型应用
抽象BaseDao
package com.wfzn.iot.utils; import cn.hutool.db.Session; import java.lang.reflect.ParameterizedType; public abstract class BaseDao<T> { private Session session; private Class clazz; public BaseDao() { Class clazz = this.getClass(); ParameterizedType pt = (ParameterizedType) clazz.getGenericSuperclass(); clazz = (Class) pt.getActualTypeArguments()[0]; System.out.println(clazz); } public void add(T t){ System.out.println(t+",增加"); } public T find(String id){ System.out.println("查找"+id); Worker worker = null; return (T)worker; } public void update(T t){ System.out.println(t+",更新"); } public void delete(String id){ System.out.println("删除"+id); } }
Worker实体类
package com.wfzn.iot.utils; import cn.hutool.db.Session; import java.lang.reflect.ParameterizedType; public abstract class BaseDao<T> { private Session session; private Class clazz; public BaseDao() { Class clazz = this.getClass(); ParameterizedType pt = (ParameterizedType) clazz.getGenericSuperclass(); clazz = (Class) pt.getActualTypeArguments()[0]; System.out.println(clazz); } public void add(T t){ System.out.println(t+",增加"); } public T find(String id){ System.out.println("查找"+id); Worker worker = null; return (T)worker; } public void update(T t){ System.out.println(t+",更新"); } public void delete(String id){ System.out.println("删除"+id); } }
WorkerDao继承BaseDao
package com.wfzn.iot.utils; public class WorkerDao extends BaseDao<Worker> { private static WorkerDao instance = new WorkerDao(); @Override public void add(Worker worker) { super.add(worker); } @Override public Worker find(String id) { return super.find(id); } @Override public void update(Worker worker) { super.update(worker); } @Override public void delete(String id) { super.delete(id); } public static void main(String[] args) { Worker worker = new Worker(); worker.setId(1); worker.setName("朱勇豪"); WorkerDao.instance.add(worker); WorkerDao.instance.find(""); WorkerDao.instance.update(worker); WorkerDao.instance.delete(""); } }
结果
附加:
TeacherDao 继承 BaseDao
package com.wfzn.iot.utils; public class TeacherDao extends BaseDao<Teacher> { private static TeacherDao instance=new TeacherDao(); @Override public void add(Teacher teacher) { super.add(teacher); } @Override public Teacher find(String id) { return super.find(id); } @Override public void update(Teacher teacher) { super.update(teacher); } @Override public void delete(String id) { super.delete(id); } public static void main(String[] args) { Teacher teacher = new Teacher(); teacher.setId(1); teacher.setName("朱勇豪"); TeacherDao.instance.add(teacher); TeacherDao.instance.find(""); TeacherDao.instance.update(teacher); TeacherDao.instance.delete(""); } }