首先用Object实现一个简单的堆栈实例:

  1. package Item29;
  2. import java.util.Arrays;
  3. import java.util.EmptyStackException;
  4. /**
  5. * @author: qujundong
  6. * @date: 2020/11/29 上午9:36
  7. * @description:
  8. */
  9. public class StackObject {
  10. private Object[] elements;
  11. private int size = 0;
  12. private static final int DEFAULT_INITIAL_CAPACITY = 16;
  13. public StackObject(){
  14. elements = new Object[DEFAULT_INITIAL_CAPACITY];
  15. }
  16. public void push(Object e){
  17. ensureCapacity();
  18. elements[size ++] = e;
  19. }
  20. public Object pop(){
  21. if(size == 0)
  22. throw new EmptyStackException();
  23. Object result = elements[--size];
  24. elements[size] = null;
  25. return result;
  26. }
  27. private boolean isEmpty(){
  28. return size == 0;
  29. }
  30. private void ensureCapacity(){
  31. if(elements.length == size){
  32. elements = Arrays.copyOf(elements, 2 * size + 1);
  33. }
  34. }
  35. @Override
  36. public String toString() {
  37. return "StackObject{" +
  38. "elements=" + Arrays.toString(elements) +
  39. ", size=" + size +
  40. '}';
  41. }
  42. public static void main(String[] args) {
  43. StackObject stack = new StackObject();
  44. stack.push(2);
  45. stack.push(4);
  46. stack.push("SS");
  47. //客户端使用的时候很容易出现类型转换上的问题,并且编译找不出错误
  48. //Integer s = (Integer)stack.pop()
  49. System.out.println(stack.pop());
  50. System.out.println(stack);
  51. }
  52. }
  53. /*
  54. SS
  55. StackObject{elements=[2, 4, null, null, null, null, null, null, null, null, null, null, null, null, null, null], size=2}
  56. */

上述代码可以存入任意类型,这有一个坏处,如果客户端进行了错误的类型转换,在编译期无法报错,这是不使用泛型的坏处,下面尝试使用泛型,但是无法新建泛型数组,有两种解决办法,分别尝试。

1. 新建Object数组,声明泛型数组引用,通过强转将Object转成E

  1. package Item29;
  2. import java.util.Arrays;
  3. import java.util.EmptyStackException;
  4. /**
  5. * @author: qujundong
  6. * @date: 2020/11/29 上午9:48
  7. * @description:
  8. */
  9. public class StackGeneric<E> {
  10. private E[] elements ;
  11. private int size = 0;
  12. private static final int DEFAULT_INITIAL_CAPACITY = 16;
  13. //因为使用类型转化会出现警告,但是确认没什么问题,所以取消未受检警告
  14. @SuppressWarnings("unchecked")
  15. public StackGeneric(){
  16. //因为无法声明泛型数组,因此使用Object[]然后转化一下类型为E[]
  17. elements = (E[])new Object[DEFAULT_INITIAL_CAPACITY];
  18. }
  19. public void push(E e){
  20. ensureCapacity();
  21. elements[size ++] = e;
  22. }
  23. public E pop(){
  24. if(size == 0)
  25. throw new EmptyStackException();
  26. E result = elements[--size];
  27. elements[size] = null;
  28. return result;
  29. }
  30. private boolean isEmpty(){
  31. return size == 0;
  32. }
  33. private void ensureCapacity(){
  34. if(elements.length == size){
  35. elements = Arrays.copyOf(elements, 2 * size + 1);
  36. }
  37. }
  38. @Override
  39. public String toString() {
  40. return "StackObject{" +
  41. "elements=" + Arrays.toString(elements) +
  42. ", size=" + size +
  43. '}';
  44. }
  45. public static void main(String[] args) {
  46. StackGeneric<Integer> stack = new StackGeneric<>();
  47. stack.push(2);
  48. stack.push(4);
  49. System.out.println(stack.pop());
  50. System.out.println(stack);
  51. }
  52. }

上述代码出现警告,因此用@SuppressWarnings(“unchecked”)解决

  1. 注: StackGeneric.java使用了未经检查或不安全的操作。
  2. 注: 有关详细信息, 请使用 -Xlint:unchecked 重新编译。

2. 新建Object数组和引用

  1. package Item29;
  2. import java.util.Arrays;
  3. import java.util.EmptyStackException;
  4. /**
  5. * @author: qujundong
  6. * @date: 2020/11/29 上午9:48
  7. * @description:
  8. */
  9. public class StackGeneric2<E> {
  10. private Object[] elements ;
  11. private int size = 0;
  12. private static final int DEFAULT_INITIAL_CAPACITY = 16;
  13. public StackGeneric2(){
  14. elements = new Object[DEFAULT_INITIAL_CAPACITY];
  15. }
  16. public void push(E e){
  17. ensureCapacity();
  18. elements[size ++] = e;
  19. }
  20. @SuppressWarnings("unchecked")
  21. public E pop(){
  22. if(size == 0)
  23. throw new EmptyStackException();
  24. //用泛型强转
  25. E result = (E)elements[--size];
  26. elements[size] = null;
  27. return result;
  28. }
  29. private boolean isEmpty(){
  30. return size == 0;
  31. }
  32. private void ensureCapacity(){
  33. if(elements.length == size){
  34. elements = Arrays.copyOf(elements, 2 * size + 1);
  35. }
  36. }
  37. @Override
  38. public String toString() {
  39. return "StackObject{" +
  40. "elements=" + Arrays.toString(elements) +
  41. ", size=" + size +
  42. '}';
  43. }
  44. public static void main(String[] args) {
  45. StackGeneric2<Integer> stack = new StackGeneric2<>();
  46. stack.push(2);
  47. stack.push(4);
  48. System.out.println(stack.pop());
  49. System.out.println(stack);
  50. }
  51. }

上述代码也会出现警告问题,不过出现在pop函数中,因此依然需要用@SuppressWarnings(“unchecked”)消除警告。
总结:使用泛型比在客户端进行类型转换要安全的多,并且也可以更早的发现错误,在编译期就解决。