目录
一般的类或者方法,只能运用具体的类型:即基本类型、自定义的类。若要编写可以用于多种类型的代码,这种刻板的限制对编写代码的束缚会很大。 ——《Java编程思想》
泛型是JDK5.1引入的语法,通俗的讲,泛型就是适用于许多的类型,代码上讲是对类型实现了参数化。
泛型是Java中比较难的语法
例如:
- class MyArray{
- public Object[] objects = new Object[10];
-
- public void set(int pos,Object val){
- objects[pos] = val;
- }
-
- public Object get(int pos){
- return objects[pos];
- }
- }
-
- public class Main {
- public static void main(String[] args) {
- MyArray myArray = new MyArray();
- myArray.set(0,"hello");
- String str = myArray.get(0);
- String str1 =
myArray.get(0); -
- System.out.println(str1);
- }
- }
对于以上代码,虽然指定了MyArray类中的objects数组类型为Object,并且在main函数中,让objects数组的0下标为字符串“hello”,但在“String str = myArray.get(0);”这行代码中会报错,只能进行强制类型转换,才可输出“hello”。
对于以上问题,就可以利用泛型。将类名改为“MyArray
上述代数可更改为:
- class MyArray
{ - public T[] objects = (T[])new Object[10];
-
- public void set(int pos,T val){
- objects[pos] = val;
- }
-
- public T get(int pos){
- return objects[pos];
- }
- }
- public class Main{
- public static void main(String[] args) {
- MyArray
myArray = new MyArray(); - myArray.set(0,"hello");
- myArray.set(1,10);
- String str = myArray.get(0);
- System.out.println(str);
- }
- }
在My Array类中,将Object类型改为T类型,在main函数中,MyArray后加上想要的类型,此时加的是
再看如下代码
- public class Main{
- public static void main(String[] args) {
- MyArray
myArray = new MyArray(); - myArray.set(0,"hello");
- myArray.set(1,10);
- String str = myArray.get(0);
- System.out.println(str);
-
- MyArray
myArray2 = new MyArray(); - MyArray<int> myArray3 = new MyArray<int>();
- }
- }
“MyArray
“MyArray
这表明对于基本类型来说,不能作为泛型类型的参数。
原类型 | 包装类 |
byte | Byte |
short | Short |
int | Integer |
long | Long |
float | Float |
double | Double |
char | Character |
boolean | Boolean |
1.数据类型参数化
2.编译时会自动进行类型的检查与转换
接下类从底层看一下泛型
在Java当前的文档中打开至这个界面,可根据
此处在空白处鼠标单击右键,选择用powershell打开,并输入指令“javap -c MyArray”,回车
发现有好多的Objec。这表名编译当中,所有的T替换为Obejct,这种替换方式称为:擦除机制
详细的泛型及泛型的擦除机制介绍:https://zhuanlan.zhihu.com/p/51452375
例如
public class MyArray
{ ......
}
此时 “MyArray
“MyArray
“MyArray
public class MyArray
{ ......
}
没有指定上界,则默认是Object,视为
这是一个寻找数组最大值的方法,类中是T类型的参数
- class Find
{ - public T findMax(T[] array){
- T max = array[0];
- for (int i = 1; i < array.length; i++) {
- if(max < array[i]){
- max = array[i];
- }
- }
- return max;
- }
- }
此时发现“ if(max < array[i])”这行代码报错了。原因是T类型是引用类型,无法通过“< ,> ,!=”等比较,需要利用compare进行比较。
则以上代码更改为
- class Find
extends Comparable>{ - public T findMax(T[] array){
- T max = array[0];
- for (int i = 1; i < array.length; i++) {
- if(max.compareTo(array[i]) < 0 ){
- max = array[i];
- }
- }
- return max;
- }
- }
测试用例:
- public class Main {
- public static void main(String[] args) {
- Integer[] array = {2,34,45,12,76,80,22,35,10};
- Find
find = new Find(); - int max = find.findMax(array);
- System.out.println("array数组最大值为: " + max);
-
- String[] strings = {"hello","i love u","qwerty"};
- Find
find2 = new Find(); - String str = find2.findMax(strings);
- System.out.println("str数组最大值为: " + str);
-
- }
-
- }
测试结果:
注意:这里的extends不是继承
通配符是为了解决泛型无法协变的问题,协变是指如果Student是Person的子类,那么List
1.泛型T是一个确定的类型,一旦传入类型就确定下来,而通配符更加灵活且不确定,更多的是用于扩充参数的范围。
2.可以理解为T就是一个变量,传入具体的类型就确定下来,而通配符可以规定能传那些参数。
例如
- class Alg{
- public static
void print1(ArrayList list) { - for (T x:list) {
- System.out.println(x);
- }
- }
-
- public static void print2(ArrayList> list){
- for (Object x:list) {
- System.out.println(list);
- }
- }
- }
语法: extends 上界>
举例:
- // 可以传入类型实参是 Integer 父类的任意类型的 MyArrayList
- public static void printAll(MyArrayList super Integer> list) {
- ...
- }
- // 以下调用都是正确的
- printAll(new MyArrayList
()); - printAll(new MyArrayList
()); - printAll(new MyArrayList
- // 以下调用是编译错误的
- printAll(new MyArrayList
()); - printAll(new MyArrayList
());