JDK 5 中引入的一个新特性, 泛型提供了编译时类型安全检测机制,该机制允许程序员在编译时检测到非法的类型。
泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。
将类型由原来的具体类型参数化,然后在使用/调用时传入具体的类型,
这个参数化可以用在类,方法,接口中
先来看看泛型的背景:
(1)需要一个排序算法,能对整型数组、字符串数组甚至其他任何类型的数组进行排序,该如何实现?——Java 泛型。
(2)如果在创建ArrayList集合时没有指定数据类型,则会默认为所有的数据类型都是object类型,此时可以往集合添加任意的数据类型。
// 创建时没有指定数据类型(即Object类型)
ArrayList list = new ArrayList();
// 此时可以添加任意数据类型
list.add(123);
list.add("hello");
// 如果我们想要获取元素,此时就会报错(即使强转有时也不行)
String s = (String)list.get(0);
这样做的坏处:在获取/使用数据时,不知道强转为什么类型,并且无法使用他的特有行为。
此时推出了泛型,可以在添加数据的时候就把类型进行统一。而且我们在获取数据的时候,也省的强转了,非常的方便。
<类型>:指定一种类型的格式
<类型1,类型2>:指定多种类型的格式
这里的类型在定义的时候可以看成形参;
而在之后调用时给定的类型可以看成实参,实参只能是引用数据类型
符号 | 含义 |
---|---|
E - Element | 在集合中使用(集合中存放的是元素) |
T - Type | Java 类 |
K - Key | 键 |
V - Value | 值 |
N - Number | 数值类型 |
? | 不确定的 java 类型 |
当一个类中,某个变量的数据类型不确定时,就可以定义带有泛型的类
class 类名
{
}
创建该类对象时,E就确定类型
可以定义自己的泛型类,例如:
public class MyArrayList <E>{
int size;
Object[] object = new Object[10];
// E表示不确定的类型,在类名后已经声明
// e 是形参
public boolean add(E e)
{
object[size] = e;
size++;
return true;
}
public E get(int index)
{
return (E)(object[index]);
}
}
创建对象(和ArrayList操作很相似):
MyArrayList<Integer> list = new MyArrayList<>();
list.add(12);
list.add(23);
int num = list.get(0);
方法中形参类型不确定时,采用泛型方法
定义格式:
修饰符 <类型> 返回值类型 方法名(类型 变量名){ }
e.g. publicvoid show(T t) { }
e.g.
public static < E > void printArray( E[] inputArray )
{
// 输出数组元素
for ( E element : inputArray ){
System.out.printf( "%s ", element );
}
System.out.println();
}
在调用时指定数据类型即可
Integer[] intArray = { 1, 2, 3, 4, 5 };
printArray( intArray ); // 传递一个整型数组
Double[] doubleArray = { 1.1, 2.2, 3.3, 4.4 };
printArray( doubleArray ); // 传递一个双精度型数组
定义格式:
修饰符 interface 接口名<类型>{ }
e.g. public interface List{ }
使用泛型接口的两种方式:
1.实现类给出具体的类型
public class MyArrayList1 implements List<String> {
}
此时需要重写List接口中的抽象方法,并且原本List接口中的泛型E都要用String进行代替,即用具体类给出具体类型
在创建对象时,也不用像泛型那样创建,可以直接和普通类对象一样(因为泛型已经被确定了)
MyArrayList1 myArrayList = new MyArrayList();
2.实现类延续泛型,在创建对象时再确定类型
public class MyArrayList2<E> implements List<E> {
}
那么在创建对象时就需要指定泛型类型
MyArrayList2<String> myArrayList = new MyArrayList2<>();
定义一个方法,形参是集合,但是集合中的类型不确定,此时可以采用泛型方法
public static<E> void method(ArrayList<E> list){
}
使用泛型方法有个缺点,就是它可以接受任意的数据类型,比如这里有四个类,分别是有继承关系的三个类Ye,Fu,Zi和另一个普通类Student类
class Ye {}
class Fu extends Ye{}
class Zi extends Fu{}
class Student{}
当只希望传递限定的类型时,可以使用通配符
通配符:?
具体用法:
? extends E:表示可以传递E或者E的所有子类类型
? super E : 表示可以传递E或者E的所有父类类型
例如当我只传递Ye Fu Zi 这三个类时,可以用通配符限定
public static void method(ArrayList<? extends Ye> list){
}
注意:
泛型不能继承,但是数据能继承
泛型指定类型后只能是该类型,他的子类或者父类是不允许的
但是数据可以有继承性:
// 声明一个方法,形参是 ArrayList 集合,集合对象是Ye对象
public static void method(ArrayList<Ye> list){
}
public static void main(String[] args) {
// 创建三个对象集合
ArrayList<Ye> list1 = new ArrayList<>();
ArrayList<Fu> list2 = new ArrayList<>();
ArrayList<Zi> list3 = new ArrayList<>();
method(list1);
/*
报错 ,因为需要的是Ye类型的对象,其他的类型对象不可以
也就是说泛型不能继承。
*/
// method(list2);
}
// 添加对象时可以
list1.add(new Ye());
list1.add(new Fu());
list1.add(new Zi());
java泛型和C++模板类很像,两者都支持参数化类型的语言功能,具体细节如果以后遇到再来补充
参考链接:
https://www.bilibili.com/video/BV17F411T7Ao?p=1&share_source=copy_web&vd_source=fa075f0e5dab81ef7c98b9eb4c47d9a7
https://www.runoob.com/java/java-tutorial.html