1 泛型的引入
问题:我们之前实现过的顺序表,只能保存 int 类型的元素,如果现在需要保存 指向 Person 类型对象的引用的顺序表,请问应该如何解决?如果又需要保存指向 Book 对象类型的引用呢?
之前写的顺序表代码示例:
import java.util.Arrays;public class MyArrayList {private int[] elem;private int usedSize;private static int capacity = 10;public MyArrayList() {this.elem = new int[capacity];}public boolean isFull() {if (this.usedSize == capacity) {return true;}return false;}public void add(int pos, int data) {if (pos < 0 || pos > this.usedSize) {System.out.println("pos位置不合法");return;}if (isFull()) {this.elem = Arrays.copyOf(this.elem, 2 * capacity);capacity *= 2;}for (int i = this.usedSize - 1; i >= pos; i--) {this.elem[i + 1] = this.elem[i];}this.elem[pos] = data;this.usedSize++;}public void display() {for (int i = 0; i < this.usedSize; i++) {System.out.print(this.elem[i] + " ");}System.out.println();}public boolean isEmpty() {if (this.usedSize == 0) {return true;}return false;}public boolean contains(int toFind) {if (isEmpty()) {return false;}for (int i = 0; i < this.usedSize; i++) {if (this.elem[i] == toFind) {return true;}}return false;}public int search(int toFind) {if (isEmpty()) {return -1;}for (int i = 0; i < this.usedSize; i++) {if (this.elem[i] == toFind) {return i;}}return -1;}public int getPos(int pos) {if (isEmpty()) {throw new RuntimeException("顺序表为空!");}if (pos < 0 || pos >= this.usedSize) {throw new RuntimeException("pos不合法");}return this.elem[pos];}public int size() {return this.usedSize;}public void setPos(int pos, int value) {if (pos < 0 || pos >= this.usedSize) {System.out.println("pos位置不合法!");return;}this.elem[pos] = value;}public void remove(int toRemove) {if (isEmpty()) {return;}int index = search(toRemove);if (index == -1) {System.out.println("没有你要删除的数字!");}for (int i = index; i < this.usedSize - 1; i++) {this.elem[i] = this.elem[i + 1];}this.usedSize--;}public void clear() {for (int i = 0; i < this.usedSize; i++) {this.elem[i] = 0;}this.usedSize = 0;}public static void main(String[] args) {MyArrayList myArrayList = new MyArrayList();myArrayList.add(0, 1);myArrayList.add(1, 2);myArrayList.add(2, 3);myArrayList.add(3, 4);System.out.println(myArrayList.size());myArrayList.display();System.out.println(myArrayList.contains(3));System.out.println(myArrayList.contains(2));System.out.println(myArrayList.search(5));System.out.println(myArrayList.search(2));System.out.println(myArrayList.getPos(0));System.out.println(myArrayList.usedSize);myArrayList.display();myArrayList.remove(1);myArrayList.remove(2);myArrayList.display();myArrayList.remove(4);myArrayList.display();myArrayList.clear();System.out.println("==============");myArrayList.display();}
}
那么,要解决上述问题,我们很自然的想到一个解决办法,将我们的顺序表的元素类型定义成 Object 类型,这样我们的 Object 类型的引用可以指向 Person 类型的对象或者指向 Book 类型的对象了。
因为代码改动较多,现在指出主要代码:
这样,我们可以就可以很自由的存储指向任意类型对象的引用到我们的顺序表了。
改编后的代码:
package test1;import java.util.Arrays;public class MyArrayList {private Object[] elem;private int usedSize;private static int capacity = 10;public MyArrayList() {this.elem = new Object[capacity];}public boolean isFull() {if (this.usedSize == capacity) {return true;}return false;}public void add(int pos, Object data) {if (pos < 0 || pos > this.usedSize) {System.out.println("pos位置不合法");return;}if (isFull()) {this.elem = Arrays.copyOf(this.elem, 2 * capacity);capacity *= 2;}for (int i = this.usedSize - 1; i >= pos; i--) {this.elem[i + 1] = this.elem[i];}this.elem[pos] = data;this.usedSize++;}public void display() {for (int i = 0; i < this.usedSize; i++) {System.out.print(this.elem[i] + " ");System.out.println();}System.out.println();}public boolean isEmpty() {if (this.usedSize == 0) {return true;}return false;}public boolean contains(Object toFind) {if (isEmpty()) {return false;}for (int i = 0; i < this.usedSize; i++) {if (this.elem[i] == toFind) {return true;}}return false;}public int search(Object toFind) {if (isEmpty()) {return -1;}for (int i = 0; i < this.usedSize; i++) {if (this.elem[i] == toFind) {return i;}}return -1;}public Object getPos(int pos) {if (isEmpty()) {throw new RuntimeException("顺序表为空!");}if (pos < 0 || pos >= this.usedSize) {throw new RuntimeException("pos不合法");}return this.elem[pos];}public int size() {return this.usedSize;}public void setPos(int pos, int value) {if (pos < 0 || pos >= this.usedSize) {System.out.println("pos位置不合法!");return;}this.elem[pos] = value;}public void remove(int toRemove) {if (isEmpty()) {return;}int index = search(toRemove);if (index == -1) {System.out.println("没有你要删除的数字!");}for (int i = index; i < this.usedSize - 1; i++) {this.elem[i] = this.elem[i + 1];}this.usedSize--;}public void clear() {for (int i = 0; i < this.usedSize; i++) {this.elem[i] = 0;}this.usedSize = 0;}public static void main(String[] args) {MyArrayList books = new MyArrayList();for (int i = 0; i < 10; i++) {books.add(i,new Book("三国演义", "罗贯中", 15));}books.display();
// MyArrayList myArrayList = new MyArrayList();
// myArrayList.add(0, 1);
// myArrayList.add(1, 2);
// myArrayList.add(2, 3);
// myArrayList.add(3, 4);
// System.out.println(myArrayList.size());
// myArrayList.display();
// System.out.println(myArrayList.contains(3));
// System.out.println(myArrayList.contains(2));
// System.out.println(myArrayList.search(5));
// System.out.println(myArrayList.search(2));
// System.out.println(myArrayList.getPos(0));
// System.out.println(myArrayList.usedSize);
// myArrayList.display();
// myArrayList.remove(1);
// myArrayList.remove(2);
// myArrayList.display();
// myArrayList.remove(4);
// myArrayList.display();
// myArrayList.clear();
// System.out.println("==============");
// myArrayList.display();}
}
遗留问题:现在的 MyArrayList 虽然可以做到添加任意类型的引用到其中了,但遇到以下代码就会产生问题。
写一个Person类:
接下来我称之为牛马操作:
编译竟然正确,没有报红,我们运行一下看看:
运行时会抛出了异常
提示:问题暴露的越早,影响越小。编译期间的问题只会让开发者感觉到,运行期间的错误会让所有的软件使用者承受错误风险。
所以我们需要一种机制,可以 1. 增加编译期间的类型检查 2. 取消类型转换的使用 泛型就此诞生!
2.泛型的分类
3 泛型类的定义的简单演示
注意: 泛型类可以一次有多个类型变量,用逗号分割。
4 泛型背后作用时期和背后的简单原理
5 泛型类的使用
通过以上代码,我们可以看到泛型类的一个使用方式:只需要在所有类型后边跟尖括号,并且尖括号内是真正的类型,即 E 可以看作的最后的类型。
看具体代码:
package test1;import java.util.Arrays;public class MyArrayList {private Object[] elem;private int usedSize;private static int capacity = 10;private E e;public MyArrayList() {this.elem = new Object[capacity];this.e = e;}public boolean isFull() {if (this.usedSize == capacity) {return true;}return false;}public void add(int pos, E data) {if (pos < 0 || pos > this.usedSize) {System.out.println("pos位置不合法");return;}if (isFull()) {this.elem = Arrays.copyOf(this.elem, 2 * capacity);capacity *= 2;}for (int i = this.usedSize - 1; i >= pos; i--) {this.elem[i + 1] = this.elem[i];}this.elem[pos] = data;this.usedSize++;}public void display() {for (int i = 0; i < this.usedSize; i++) {System.out.print(this.elem[i] + " ");System.out.println();}System.out.println();}public boolean isEmpty() {if (this.usedSize == 0) {return true;}return false;}public boolean contains(E toFind) {if (isEmpty()) {return false;}for (int i = 0; i < this.usedSize; i++) {if (this.elem[i] == toFind) {return true;}}return false;}public int search(E toFind) {if (isEmpty()) {return -1;}for (int i = 0; i < this.usedSize; i++) {if (this.elem[i] == toFind) {return i;}}return -1;}public Object getPos(int pos) {if (isEmpty()) {throw new RuntimeException("顺序表为空!");}if (pos < 0 || pos >= this.usedSize) {throw new RuntimeException("pos不合法");}return this.elem[pos];}public int size() {return this.usedSize;}public void setPos(int pos, int value) {if (pos < 0 || pos >= this.usedSize) {System.out.println("pos位置不合法!");return;}this.elem[pos] = value;}public void remove(E toRemove) {if (isEmpty()) {return;}int index = search(toRemove);if (index == -1) {System.out.println("没有你要删除的数字!");}for (int i = index; i < this.usedSize - 1; i++) {this.elem[i] = this.elem[i + 1];}this.usedSize--;}public void clear() {for (int i = 0; i < this.usedSize; i++) {this.elem[i] = 0;}this.usedSize = 0;}public static void main(String[] args) {MyArrayList books = new MyArrayList();books.add(0, new Book("红楼梦", "曹雪芹", 18));books.add(2, new Person("lisi", "lll"));// Book book1 = new Book("红楼梦", "曹雪芹", 18);
// for (int i = 0; i < 10; i++) {
// if (i == 0) {
// books.add(i, book1);
// } else {
// books.add(i, new Book("三国演义", "罗贯中", 15));
// }
// }
// books.display();
// Person person = (Person) books.getPos(0);
// MyArrayList myArrayList = new MyArrayList();
// myArrayList.add(0, 1);
// myArrayList.add(1, 2);
// myArrayList.add(2, 3);
// myArrayList.add(3, 4);
// System.out.println(myArrayList.size());
// myArrayList.display();
// System.out.println(myArrayList.contains(3));
// System.out.println(myArrayList.contains(2));
// System.out.println(myArrayList.search(5));
// System.out.println(myArrayList.search(2));
// System.out.println(myArrayList.getPos(0));
// System.out.println(myArrayList.usedSize);
// myArrayList.display();
// myArrayList.remove(1);
// myArrayList.remove(2);
// myArrayList.display();
// myArrayList.remove(4);
// myArrayList.display();
// myArrayList.clear();
// System.out.println("==============");
// myArrayList.display();}
}
那么现在就会出现编译错误 ,这就是泛型的作用!
注意: Book 只能想象成 E 的类型,但实际上 E 的类型还是 Object。
6 泛型总结