ThinkChat🤖让你学习和工作更高效,注册即送10W Token,即刻开启你的AI之旅 广告
## 泛型 ### 基本概念 很多时候我们关心的不是数据类型,而是能力,针对接口和能力编程,不仅可以复用代码,还可以降低耦合,提高灵活性。 `泛型`的字面意思就是**广泛的类型**;类、接口和方法代码可以应用于非常广泛的类型,代码与它们能够操作的数据类型不再绑定在一起,同一套代码可以用于多种数据类型,这样,不仅可以复用代码,降低耦合,而且可以提高代码的可读性和安全性。 ### 泛型基本概念 ``` class Pair<Z, V>{ Z first; V second; public Pair(Z first, V second) { this.first = first; this.second = second; } public Z getFirst() { return first; } public V getSecond() { return second; } } ``` - 类名后面多了```<Z> <V>```; - ```<Z> <V>```是什么呢?```<Z> <V>```表示类型参数,泛型就是类型参数化,处理的数据类型不是固定的,而是可以作为参数传入。怎么用这个泛型类,并传递类型参数呢? ``` Pair<Integer, String> pair = new Pair<Integer, String>(111, "222"); System.out.println(pair.getFirst() + " " + pair.getSecond()); Pair<Double, Float> pairStr = new Pair<Double, Float>(1.2, 3.2f); System.out.println(pairStr.getFirst() + " " + pairStr.getSecond()); ``` ### 基本原理 泛型类型参数到底是什么呢?为什么一定要定义类型参数呢?定义普通类,直接使用Object不就行了吗?比如,Pair类可以写为: ``` class Pair { Object first; Object second; public Pair(Object first, Object second) { this.first = first; this.second = second; } public Object getFirst() { return first; } public Object getSecond() { return second; } } Pair pair = new Pair(111, "aaa"); System.out.println(pair.getFirst() + " " + pair.getSecond()); Pair pair2 = new Pair(1.2, 3.2f); System.out.println(pair2.getFirst() + " " + pair2.getSecond()); ``` 这样是可以的。实际上,Java泛型的内部原理就是这样的。 > Java有Java编译器和Java虚拟机,编译器将Java源代码转换为.class文件,虚拟机加载并运行.class文件。对于泛型类,Java编译器会将泛型代码转换为普通的非泛型代码,就像上面的普通Pair类代码及其使用代码一样,将类型参数T擦除,替换为Object,插入必要的强制类型转换。Java虚拟机实际执行的时候,它是不知道泛型这回事的,只知道普通的类及代码。Java泛型是通过擦除实现的,类定义中的类型参数如`<T>`会被替换为Object,在程序运行过程中,不知道泛型的实际类型参数,比如`Pair<Integer>`,运行中只知道Pair,而不知道Integer。认识到这一点是非常重要的,它有助于我们理解Java泛型的很多限制。 ### 泛型的好处 * 类型安全 ``` // 把运行时异常转换为编译时异常 Pair<Integer, String> pair3 = new Pair<Integer, String>(111, 222); ``` * 消除强制类型转换 ### 小栗子 ``` // 自定义数组 class DynamicArray<T> { // 默认的一个长度 private static final int DEFAULT_CAPACITY = 10; // 初始化size 默认为0 private int size; // 数组 private Object[] elementData; // 构造方法 public DynamicArray() { elementData = new Object[DEFAULT_CAPACITY]; } // 需要长大 private void grow(int minCapacity) { int oldSize = elementData.length; if (oldSize >= minCapacity) { System.out.println("没有达到扩充数组的地步 " + minCapacity); return; } int newCapacity = oldSize * 2; System.out.println("扩充后的长度 " + newCapacity); // 扩充 elementData = Arrays.copyOf(elementData, newCapacity); } // 添加方法 public Boolean add(T t) { grow(size + 1); elementData[size] = t; size = size + 1; return true; } // 获取元素 public T get(int index) { return (T)elementData[index]; } // 获取size public int size() { return size; } } // 调用 // 支持各种类型 Doublue Integer new Pair<String, Integer>() // Double DynamicArray<Double> arr = new DynamicArray<Double>(); Random random = new Random(); int size = 1+ random.nextInt(100); for (int i = 0; i < size; i++) { arr.add(Math.random()); } Double d = arr.get(random.nextInt(size)); System.out.println(d + " / " + arr.size()); // Integer DynamicArray<Integer> arr2 = new DynamicArray<Integer>(); arr2.add(12); System.out.println("\n" + arr2.get(0)); // 自定义对象 DynamicArray<Pair<String, Integer>> arr3 = new DynamicArray<Pair<String, Integer>>(); Pair<String, Integer> pair = new Pair<String, Integer>("aaa", 23); arr3.add(pair); System.out.println("\n" + arr3.get(0).toString()); ``` 这就是一个简单的容器类,适用于各种数据类型。