java泛型的使用

泛型知识点

一、泛型及其作用

1.没有泛型的情况下,定义一个数组列表
  1. package main.java.com.shixinke.java.demo.generic;
  2. /**
  3. * 定义一个整型的数组列表
  4. */
  5. class MyIntList {
  6. private Integer[] elements;
  7. private int size;
  8. public MyIntList(int capacity) {
  9. if (capacity < 1) {
  10. capacity = 1;
  11. }
  12. this.elements = new Integer[capacity];
  13. }
  14. public int size() {
  15. return this.size;
  16. }
  17. public void add(int v) {
  18. if (this.size == this.elements.length) {
  19. ensureCapacity(this.size * 2);
  20. }
  21. this.elements[this.size] = v;
  22. this.size ++;
  23. }
  24. public Integer remove(int i) {
  25. if (i < 0 || i >= this.size) {
  26. return null;
  27. }
  28. Integer v = this.elements[i];
  29. this.size --;
  30. if (i == this.size) {
  31. this.elements[i] = null;
  32. return v;
  33. }
  34. for (int j = i; j< this.size; j++) {
  35. this.elements[j] = this.elements[j+1];
  36. }
  37. this.elements[this.size] = null;
  38. return v;
  39. }
  40. public Integer get(int i) {
  41. if (i < 0 || i >= this.size) {
  42. return null;
  43. }
  44. return this.elements[i];
  45. }
  46. private void ensureCapacity(int capacity) {
  47. if (capacity <= this.elements.length) {
  48. return;
  49. }
  50. Integer[] oldData = this.elements;
  51. this.elements = new Integer[capacity];
  52. for (int i = 0; i< oldData.length; i++) {
  53. this.elements[i] = oldData[i];
  54. }
  55. }
  56. }
  57. /**
  58. * 定义一个字符串型的数组列表
  59. */
  60. class MyStrList {
  61. private String[] elements;
  62. private int size;
  63. public MyStrList(int capacity) {
  64. if (capacity < 1) {
  65. capacity = 1;
  66. }
  67. this.elements = new String[capacity];
  68. }
  69. public int size() {
  70. return this.size;
  71. }
  72. public void add(String v) {
  73. if (this.size == this.elements.length) {
  74. ensureCapacity(this.size * 2);
  75. }
  76. this.elements[this.size] = v;
  77. this.size ++;
  78. }
  79. public String remove(int i) {
  80. if (i < 0 || i >= this.size) {
  81. return null;
  82. }
  83. String v = this.elements[i];
  84. this.size --;
  85. if (i == this.size) {
  86. this.elements[i] = null;
  87. return v;
  88. }
  89. for (int j = i; j< this.size; j++) {
  90. this.elements[j] = this.elements[j+1];
  91. }
  92. this.elements[this.size] = null;
  93. return v;
  94. }
  95. public String get(int i) {
  96. if (i < 0 || i >= this.size) {
  97. return null;
  98. }
  99. return this.elements[i];
  100. }
  101. private void ensureCapacity(int capacity) {
  102. if (capacity <= this.elements.length) {
  103. return;
  104. }
  105. String[] oldData = this.elements;
  106. this.elements = new String[capacity];
  107. for (int i = 0; i< oldData.length; i++) {
  108. this.elements[i] = oldData[i];
  109. }
  110. }
  111. }
  112. public class ListDemo {
  113. public static void main(String[] args) {
  114. MyIntList list1 = new MyIntList(5);
  115. list1.add(5);
  116. list1.add(8);
  117. for (int i = 0; i< list1.size(); i++) {
  118. System.out.println(list1.get(i));
  119. }
  120. MyStrList list2 = new MyStrList(5);
  121. list2.add("h");
  122. list2.add("e");
  123. for (int i = 0; i< list2.size(); i++) {
  124. System.out.println(list2.get(i));
  125. }
  126. }
  127. }
  • 上例可以看到一个数组列表,因为其数组元素数据类型不同,得定义两个结构非常雷同的代码
2.泛型
  • 泛型是将数据类型进行抽象,提高代码复用性而产生的

通过泛型,我们来将上面的二个类合二为一:

  1. class MyList<T> {
  2. private T[] elements;
  3. private int size;
  4. public MyList(int capacity) {
  5. if (capacity < 1) {
  6. capacity = 1;
  7. }
  8. this.elements = (T[])new Object[capacity];
  9. }
  10. public int size() {
  11. return this.size;
  12. }
  13. public void add(T v) {
  14. if (this.size == this.elements.length) {
  15. ensureCapacity(this.size * 2);
  16. }
  17. this.elements[this.size] = v;
  18. this.size ++;
  19. }
  20. public T remove(int i) {
  21. if (i < 0 || i >= this.size) {
  22. return null;
  23. }
  24. T v = (T)this.elements[i];
  25. this.size --;
  26. if (i == this.size) {
  27. this.elements[i] = null;
  28. return v;
  29. }
  30. for (int j = i; j< this.size; j++) {
  31. this.elements[j] = this.elements[j+1];
  32. }
  33. this.elements[this.size] = null;
  34. return v;
  35. }
  36. public T get(int i) {
  37. if (i < 0 || i >= this.size) {
  38. return null;
  39. }
  40. return (T)this.elements[i];
  41. }
  42. private void ensureCapacity(int capacity) {
  43. if (capacity <= this.elements.length) {
  44. return;
  45. }
  46. T[] oldData = this.elements;
  47. this.elements = (T[])new Object[capacity];
  48. for (int i = 0; i< oldData.length; i++) {
  49. this.elements[i] = oldData[i];
  50. }
  51. }
  52. }

二、泛型的基本使用

1.泛型类
  • 在定义类的时候,在类名后面加上类似于的标识
  1. /**
  2. * 响应类
  3. */
  4. class Response<T> {
  5. private int code;
  6. private String message;
  7. private T data;
  8. public int getCode() {
  9. return code;
  10. }
  11. public void setCode(int code) {
  12. this.code = code;
  13. }
  14. public String getMessage() {
  15. return message;
  16. }
  17. public void setMessage(String message) {
  18. this.message = message;
  19. }
  20. public T getData() {
  21. return data;
  22. }
  23. public void setData(T data) {
  24. this.data = data;
  25. }
  26. }

注:因为我们的每个接口响应的数据一般不一样,所以用泛型来代替,根据具体的返回对象进行实例化半设置返回数据的类型即可

2.泛型接口
  • 与定义普通的接口相比,只是在接口名称后面加上了一个类型于这样的泛型
  1. interface Sortable<T> {
  2. T sort(T obj);
  3. }

注:因为排序接口,是一个通用的接口定义,具体的可能是数字排序,也可能是字符串排序等

3.泛型方法
  • 泛型方法可以在泛型类中使用,也可以不在泛型类中使用
  • 它是在方法的返回类型前面添加一个泛型标识
  1. class Cache {
  2. /**
  3. * 在返回类型List<T>前面有一个<T>这样的泛型标识
  4. */
  5. public <T> List<T> mget(List<String> keys) {
  6. return new ArrayList<>();
  7. }
  8. }

注:类不是泛型类,但可以定义泛型方法

4.泛型类型变量的限定
  • 通过:限制T必须是继承自Number类型
  1. class Point<T extends Number> {
  2. private T x;
  3. private T y;
  4. public Point (T x, T y) {
  5. this.x = x;
  6. this.y = y;
  7. }
  8. }
  9. public class InterfaceDemo {
  10. public static void main(String[] args) {
  11. //可以使用Integer型或Double类型,因为它们都是Number的子类
  12. Point<Integer> p = new Point<Integer>(10, 20);
  13. Point<Double> p2 = new Point<Double>(10.1, 20.1);
  14. //而使用String却不可以,因为String不是Number的子类
  15. //Point<String> p3 = new Point<String>("1", "2");
  16. }
  17. }

三、泛型的高级使用

1.通配符
  • 通过<? extends List>:限制通配符类型必须继承自List
  • 通过<? super Collection>:限制通配符类型只要是Collection的子类即可
  • 无限制通配符?
  1. class Point<T> {
  2. private T x;
  3. private T y;
  4. public Point (T x, T y) {
  5. this.x = x;
  6. this.y = y;
  7. }
  8. }
  9. class Comparator {
  10. /**
  11. * 参数p1和p2必须继承自Number
  12. */
  13. public static void compare(Point<? extends Number> p1, Point<? extends Number> p2) {
  14. }
  15. /**
  16. * 参数p1和p2只要是Collection的子类即可
  17. */
  18. public static void compareTo(Point<? super Collection> p1, Point<? super Collection> p2) {
  19. }
  20. }
  21. public class GenericDemo {
  22. public static void main(String[] args) {
  23. Comparator.compare(new Point(12, 13), new Point(13.5, 14.5));
  24. Comparator.compareTo(new Point(new ArrayList(), new ArrayList()), new Point(new ArrayList(), new ArrayList()));
  25. }
  26. }