后面的文章:
- 详解 Java 的对象创立
- 一文打尽 Java 继承的相干问题
- 一文打尽 Java 抽象类和接口的相干问题
本文介绍了 Java 的泛型的根本应用。
1. 为什么应用泛型
看上面一个例子:
为了阐明问题,本类写的尽量简陋,请把眼光次要放在类型上。
/**
* @author Xing Xiaoguan (xingrenguanxue)
*/
public class MyArrayList {private int[] elementData;
private int size = 0;
public MyArrayList(int capacity) {elementData = new int[capacity];
}
// 向数组中增加元素
public void add(int i) {if (size == elementData.length) {throw new IndexOutOfBoundsException("数组已满");
}
elementData[size++] = i;
}
// 从数组中依据下标获取元素
public int get(int index) {if (index < 0 || index > size - 1) {throw new IndexOutOfBoundsException("超出范围");
}
return elementData[index];
}
@Override
public String toString() {
return "MyArrayList{" +
"elementData=" + Arrays.toString(elementData) +
'}';
}
}
该类很简略:有两个成员变量,elementData
是一个数组,size
是数组中元素的数量。add
和 get
办法能增加和获取元素。
上面测试一下:
public class Test {public static void main(String[] args) {MyArrayList myArrayList = new MyArrayList(4);
myArrayList.add(111); // 向数组中增加 3 个 int 元素
myArrayList.add(222);
myArrayList.add(333);
int i = myArrayList.get(0); // 获取
System.out.println(i);
// 以上失常运行
myArrayList.add("行小观"); // 增加一个 String 元素,类型不匹配,报错
}
}
向数组中增加 3 个 int
类型的元素并能获取,这没问题。
然而如果咱们的场景不再须要 int
类型的元素,而是须要 String
类型的,那怎么办?
很显然,持续应用该类会报错,报错的起因很简略:咱们向数组中增加的元素是 String
类型的,而数组和办法参数类型是 int
类型。
此时,就得须要再写一份代码,该份代码较之前的并无大批改,只是把 int
改为String
。如果场景持续变怎么办?那就再写一份新代码!
这样太麻烦了!有没有解决办法?有!
咱们晓得,Object
类是所有类的父类,Object
类型的变量可能援用任何类型的对象。所以能够将类型改为Object
:
/**
* @author Xing Xiaoguan (xingrenguanxue)
*/
public class MyArrayList {private Object[] elementData;
private int size = 0;
public MyArrayList(int capacity) {elementData = new Object[capacity];
}
public void add(Object o) { // 向数组中增加元素
if (size == elementData.length) {throw new IndexOutOfBoundsException("数组已满");
}
elementData[size++] = o;
}
public Object get(int index) { // 从数组中获取元素
if (index < 0 || index > size - 1) {throw new IndexOutOfBoundsException("超出范围");
}
return elementData[index];
}
@Override
public String toString() {
return "MyArrayList{" +
"elementData=" + Arrays.toString(elementData) +
'}';
}
}
再测试一下:
public class Test {public static void main(String[] args) {
//myArrayList 给 int 元素应用
MyArrayList myArrayList = new MyArrayList(4);
myArrayList.add(111); // 向数组中增加 3 个 int 元素
myArrayList.add(222);
myArrayList.add(333);
int i = (int) myArrayList.get(0); // 获取
System.out.println(i);
//myArrayList 给 String 元素应用
MyArrayList myArrayList1 = new MyArrayList(4);
myArrayList1.add("aaa");
myArrayList1.add("bbb");
myArrayList1.add("ccc");
String str = (String) myArrayList1.get(1);
System.out.println(str);
}
}
发现能够向数组中增加和获取 int
或String
类型的元素,这证实该类的数组和办法同时对各种类型的数据都有用,不用再增加额定代码。
然而这样又呈现了两个问题:
第一:从数组中获取元素时,须要强制转换类型才行。
int i = (int) myArrayList.get(0);
第二:同一个数组能够增加各种类型的元素。
myArrayList.add(111); //int 类型
myArrayList.add("222"); //String 类型
myArrayList.add(true); // 布尔类型
这就导致了当咱们从数组中获取某个元素时,很难晓得它的确切类型,往往会强转类型失败。
int i = (int)myArrayList.get(1); // 原本是 String 类型的值,但我提前不晓得,拿 int 变量接管,报错
那这个问题有没有解决办法呢?
有!用泛型!
2. 泛型类
应用泛型革新MyArrayList
:
/**
* @author Xing Xiaoguan (xingrenguanxue)
*/
public class MyArrayList <T> {private T[] elementData;
private int size = 0;
public MyArrayList(int capacity) {elementData = (T[]) new Object[capacity];
}
public void add(T o) { // 向数组中增加元素
if (size == elementData.length) {throw new IndexOutOfBoundsException("数组已满");
}
elementData[size++] = o;
}
public T get(int index) { // 从数组中获取元素
if (index < 0 || index > size - 1) {throw new IndexOutOfBoundsException("超出范围");
}
return elementData[index];
}
@Override
public String toString() {
return "MyArrayList{" +
"elementData=" + Arrays.toString(elementData) +
'}';
}
}
测试:
public class Test {public static void main(String[] args) {
//myArrayList 给 int 元素应用
MyArrayList<Integer> myArrayList = new MyArrayList<>(4);
myArrayList.add(111); // 向数组中增加 3 个 int 元素
// myArrayList.add("222"); // 增加非 Integer 元素报错
int i = myArrayList.get(1); // 无需强制转型
System.out.println(i);
}
}
通过革新,咱们把 MyArrayList
类改为了一个 泛型类,它是一个具备多个类型变量的类。
泛型类的申明形式:引入一个类型变量,如 T,而后应用 <> 将其括起来,放在类名后。
public class MyArrayList <T> {//......}
如何了解类型变量?它就相似于数学中函数中的变量 x,用来代替具体的值:
f(x) = 3x + 1
类型变量的名称能够轻易取,个别应用大写字母示意,比方 E、K、V、T 等。
泛型类中的成员变量、办法参数和返回值的类型都应用类型变量代替:
private T[] elementData;
public void add(T o) {//.......}
public T get(int index) {//......}
当然,一个泛型类能够有多个类型变量:
public class MyClass <K, V> {//......}
当咱们须要实例化泛型类时,就应用具体的类型来替换类型变量(T):
MyArrayList<Integer> myArrayList = new MyArrayList<>(4);
该过程就相当于向数学函数中代入数值:
f(3) = 3*3+1 = 10
3. 泛型办法
当咱们申明了一个泛型类后,能够很天然地在类外部应用泛型办法。
其实,当类是一般类时,咱们依然可能应用泛型办法。上面是一个例子:
/**
* @author Xing Xiaoguan (xingrenguanxue)
*/
public class PrinterVar {
// 该办法接管一个 T 类型的变量,打印并返回该变量
public <T> T print(T var) {System.out.println(var);
return var;
}
public static void main(String[] args) {PrinterVar printerVar = new PrinterVar();
String var = printerVar.print("aa");//String 类型
Integer var1 = printerVar.print(12);//int 类型
System.out.println(var + " " + var1);
}
}
4. 对于我
点击这里意识我。(^o^)/