什么是泛型

泛型是提供给javac编译器使用的,可以限定集合中的输入类型,让编译器挡住源程序中的非法输入,编译器编译带类型说明的集合时会去除掉”类型”信息,是程序的运行效率不受影响,对于参数化的泛型类型,getClass()方法返回值和原始类型完全一样。由于编译生成的字节码会擦除泛型的类型信息,只要能跳过编译器,就可以往某个泛型集合中加入其它类型的数据,例如,用反射得到集合,然后再调用add()方法即可

GenericDemo.java

  1. public class GenericDemo {
  2.  
  3. public static void main(String[] args) {
  4.  
  5. // 未使用泛型,则可以添加任意Object类型的数据
  6. List noGrnerics = new ArrayList<>();
  7. noGrnerics.add(1);
  8. noGrnerics.add("hello");
  9. noGrnerics.add("1L");
  10. noGrnerics.add(new GenericDomain(1L,"Generic"));
  11. // 由于没有使用泛型,在取出数据时必须要知道某个位置上的某个数据的数据类型,并加以强制转换,否则要出错,除非用Object接收。
  12. Integer integer = (Integer) noGrnerics.get(0);
  13. System.out.println("integer = " + integer);
  14. // 由于不知道某个位置上的数据类型,用Object接收
  15. Object objIndex1 = noGrnerics.get(1);
  16. System.out.println("objIndex1 = " + objIndex1);
  17. Object objeIndex3 = noGrnerics.get(3);
  18. System.out.println("objeIndex3 = " + objeIndex3);
  19. // 虽然可以通过类对象来知道类属性,但是这样不是太麻烦了吗??
  20. System.out.println("objeIndex3.getClass() = " + objeIndex3.getClass());
  21.  
  22. // 使用泛型
  23. List<String> strs = new ArrayList<>();
  24. strs.add("str1");
  25. strs.add("str2");
  26. strs.add("str3");
  27. // 因为指定了这个List中只能放置String类型的数据,当这里放置其他类型的数据时就会报错,因为不能装进去
  28. // 从某种角度上可以认为泛型解决了强制类型转换,使数据特征更明显,拥有一致性
  29. // strs.add(1);
  30. String str = strs.get(0);
  31. System.out.println("str = " + str);
  32.  
  33. }
  34.  
  35. }

绕过编译时泛型,添加非泛型类型数据:GenericDemo2.java

  1. public class GenericDemo2 {
  2.  
  3. /**
  4. * 程序目标,向一个List<String>的泛型数组中添加Integer类型的数据
  5. *
  6. * @param args
  7. */
  8. public static void main(String[] args) {
  9.  
  10. List<String> strs = new ArrayList<>();
  11. strs.add("str1");
  12. strs.add("str2");
  13. strs.add("str3");
  14. strs.add("str4");
  15. // 这里是添加不进去的,因为指定了泛型类型,且没有泛型擦除
  16. // strs.add(new Integer(1));
  17. System.out.println("Before add a Integer value : " + strs);
  18.  
  19. // 通过泛型在运行时擦除的原理,利用反射向泛型中添加Integer数据
  20. Class<List<String>> clazz = (Class<List<String>>) strs.getClass();
  21. try {
  22. // 这里在利用反射获取add方法时,如果参数类型指定为String.class,
  23. // 则说明add方法为,java.util.ArrayList.add(java.lang.String)
  24. // 而我们传入了一个Integer类型的数据,则显然不能添加成功,会抛出 java.lang.NoSuchMethodException
  25. clazz.getDeclaredMethod("add", String.class).invoke(strs, new Integer(1));
  26. // 这里原因一样,java.util.ArrayList.add(java.lang.Integer) 但是用的int,
  27. // 请记住,java是强类型语言,这里不存在自动装箱和拆箱
  28. clazz.getDeclaredMethod("add", Integer.class).invoke(strs, 2);
  29. // 这里也是不正确的,因为Class<List<String>>指定了放String
  30. clazz.getDeclaredMethod("add", Integer.class).invoke(strs, new Integer(4));
  31. //同上
  32. clazz.getDeclaredMethod("add", int.class).invoke(strs, 5);
  33. } catch (Exception e) {
  34. e.printStackTrace();
  35. } finally {
  36. //正确做法
  37. try {
  38. clazz.getDeclaredMethod("add", Object.class).invoke(strs, 3);
  39. System.out.println("strs = " + strs);
  40. // 只有Object能行
  41. clazz.getDeclaredMethod("add", String.class).invoke(strs, "4");
  42. System.out.println("strs = " + strs);
  43. } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException
  44. | NoSuchMethodException | SecurityException e) {
  45. // TODO Auto-generated catch block
  46. e.printStackTrace();
  47. }
  48. }
  49. System.out.println("After add a Integer value : " + strs);
  50. }
  51.  
  52. }

解释为什么只能用Object,运行时会擦除泛型,下面的代码清单就可以验证

  1. public class GenericTypeDemo {
  2.  
  3. public static void main(String[] args) {
  4. // 这里的字节码类型为ArrayList
  5. List<String> strings = new ArrayList<>();
  6. // 这里的字节码类型也为ArrayList
  7. List<Integer> integers = new ArrayList<>();
  8. System.out.println("strings.getClass() = " + strings.getClass());
  9. System.out.println("integers.getClass() = " + integers.getClass());
  10. System.out.println("integers.getClass() == strings.getClass() = "
  11. + (integers.getClass() == strings.getClass()));
  12. }
  13.  
  14. }

泛型中的?通配符

  • 需求:定义一个方法,该方法用于打印出任意参数类型化的集合中的所有数据。
  1. public class GenericDemo3 {
  2.  
  3. public static void main(String[] args) {
  4.  
  5. // 需求:定义一个方法,该方法用于打印出任意参数类型化的集合中的所有数据。
  6. List<String> strings = new ArrayList<>();
  7. strings.add("a");
  8. strings.add("b");
  9. strings.add("c");
  10. strings.add("f");
  11. printCollectionElements(strings);
  12. printStringCollectionElements(strings);
  13. List<Integer> integers = new ArrayList<>();
  14. integers.add(1);
  15. integers.add(2);
  16. integers.add(3);
  17. integers.add(4);
  18. printCollectionElements(integers);
  19. // 这里就不能用了
  20. // printStringCollectionElements(integers);
  21.  
  22. }
  23.  
  24. /**
  25. * 定义一个方法,该方法用于打印出任意参数类型化的集合中的所有数据。
  26. * 这种是通配方法,能够打印所有的,其通配之处就在与?,?可以引用其他各种参数化的类型
  27. * @param collection
  28. */
  29. public static void printCollectionElements(Collection<?> collection) {
  30. collection.forEach(System.out::println);
  31. }
  32.  
  33. /**
  34. * 打印String类型的集合数据,由于制定了泛型类型为String,则只能打印String类型的集合
  35. * @param collection
  36. */
  37. public static void printStringCollectionElements(Collection<String> collection) {
  38. collection.forEach(System.out::println);
  39. }
  40.  
  41. }
  • 总结

使用?通配符可以引用其他各种参数化的类型,?通配符定义的变量主要用作引用,可以调用与参数化无关的方法,如size(),不能调用与参数化有关的方法,如add(E e)

泛型中?的扩展

  • 限定通配符的上边界
    • 正确 List<? extends Number> x = new ArrayList<Integer>();
    • 错误 List<? extends Number> x = new ArrayList<String>();
  • 限定通配符的下边界
    • 正确 Vector<? super Integer> x = new Vector<Number>();
    • 错误 Vector<? super Integer> x = new Vector<Byte>();
  • 总结
    • 限定通配符总是包括自己

JAVA基础_泛型的更多相关文章

  1. 黑马程序员:Java基础总结----泛型(高级)

    黑马程序员:Java基础总结 泛型(高级)   ASP.Net+Android+IO开发 . .Net培训 .期待与您交流! 泛型(高级) 泛型是提供给javac编译器使用的,可以限定集合中的输入类型 ...

  2. JAVA基础_自定义泛型

    泛型的来源 在Java中,泛型借鉴了C++的模版函数,从而引入了泛型. C++泛型 int add(int x,int y){ return x + y; } float add(float x.fl ...

  3. 黑马程序员——JAVA基础之泛型和通配符

    ------- android培训.java培训.期待与您交流! ---------- 泛型:            JDK1.5版本以后出现新特性.用于解决安全问题,是一个类型安全机制. 泛型好处: ...

  4. Java基础知识--泛型

    什么是泛型?为什么使用泛型? 泛型,就是参数化类型.提到参数,最熟悉的就是定义方法时候的形参,然后调用此方法时传递实参.顾名思义,就是将类型由原来的具体的类型参数化,类似于方法中的变量参数,此时类型也 ...

  5. JAVA基础_反射获取泛型参数类型

    我经常会想获取参数的实际类型,在Hibernate中就利用的这一点. domain: Person.java public class Person { // 编号 private Long id; ...

  6. Java基础:泛型

    Java的泛型是什么呢, 就是类型的參数化,这得类型包含方法參数和返回值.也就是原本该是确定类型的地方换成了变量,把类型的确定时间向后延迟了. 在之前,学过"重载"的概念,重载是什 ...

  7. Java基础教程——泛型

    泛型 Generics:泛型,愿意指"无商标的". 泛型,可以理解为"宽泛的数据类型",就是将类型由原来的具体的类型泛化. 泛型在建立对象时不指定类中属性的具体 ...

  8. 【Java基础】泛型

    Num1:请不要在新代码中使用原生类型 泛型类和接口统称为泛型.每种泛型定义一组参数化的类型,构成格式是:类或接口名称,接着用<>把对应于泛型形式类型的参数的实际参数列表括起来.比如:Li ...

  9. 黑马程序员——【Java基础】——泛型、Utilities工具类、其他对象API

    ---------- android培训.java培训.期待与您交流! ---------- 一.泛型 (一)泛型概述 1.泛型:JDK1.5版本以后出现的新特性,用于解决安全问题,是一个类型安全机制 ...

随机推荐

  1. ES6点点点运算符

    1. rest(可变)参数 * 用来取代arguments 但比arguments灵活,只能是最后部分形参参数 function add(...values) { let sum = ; for(va ...

  2. 最佳实践:阿里云VPC、ECS支持IPv6啦!

    12月6日,阿里云宣布为企业提供全栈IPv6解决方案. 阿里云专有网络VPC.云服务器ECS,作为阿里云的核心产品,也于2018年11月底上线双栈VPC.双栈ECS,目前正在对外公测中. 那么如何在阿 ...

  3. bzoj1024题解

    [解题思路] 爆搜,状态f(r,x,y)表示剩下r刀,边长为x和y,对于每个状态枚举切成两块后的长度比或宽度比.复杂度o((n/2)n). [参考代码] #include <algorithm& ...

  4. NX二次开发-创建圆弧(起点-终点-半径)UF_CURVE_create_arc_point_point_radius

    NX9+VS2012 #include <uf.h> #include <uf_curve.h> UF_initialize(); //起点 ]; ArcStartPoint[ ...

  5. Codeforces786B

    传送门 n个节点且固定起点最短路,三种加边方法 1.u->v, 边权为w:2. u->[l, r], 边权为w:3. [l, r]->u, 边权为w AC_Code #include ...

  6. jsp-解决自写Servlet老是报错404

    写好servlet进行测试老是报404解决方案. 1.确保web.xml配置好 2.Bulid Path项目,在Libraries界面Add External JARs,在tomcat的lib目录下面 ...

  7. sklearn参数优化

    学习器模型中一般有两个参数:一类参数可以从数据中学习估计得到,还有一类参数无法从数据中估计,只能靠人的经验进行指定,后一类参数就叫超参数 比如,支持向量机里的C,Kernel,gama,朴素贝叶斯里的 ...

  8. Opencv稍微高级点的鼠标事件-OpenCV步步精深

    今天我们要来点稍微高级的东西.在我们按下鼠标时可以画矩形,而我们按下键盘m键时,切换到画圆的模式,再按下m键,回到画矩形模式. 一起来写下代码,首先当然还是调用库 import cv2 import ...

  9. 6-Python操作MySQL-增(insert)-删(delete)-改(update)-查(select)

    增删改 from pymysql import * def main(): # 创建Connection连接 conn = connect(host='localhost',port=3306,dat ...

  10. Codeforces Round #526 C - The Fair Nut and String /// 组合递推

    题目大意: 给定原字符序列 找出其中所有子序列满足 1.序列内字符都为a 2.若有两个以上的字符 则相邻两个字符在原序列中两者之间存在字符b 的数量 将整个字符序列用b分开 此时再得到每个b之间a的数 ...