开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第5天,点击查看活动详情
泛型
Java 中有 8 种基本数据类型和类(自定义数据类型),类之间可以组合或者继承
而正是由于我们更加关注的是能力,而不是类,所以有了接口的概念,它不仅可以复用代码,而且可以降低代码耦合,提高灵活性
泛型是计算机程序的一种重要的思维方式,他将数据结构和算法与数据类型分离,使得同一套数据结构和算法能够应用于各种数据类型,而且能保证类型的安全性,提高可读性。
例子
public class test01 {
public static void main(String[] args) {
Pair<Integer> minmax = new Pair<Integer>(1,100);
Integer min = minmax.getFirst();
Integer max = minmax.getSecond();
System.out.println(min);
System.out.println(max);
Pair<String> kv = new Pair<String>("name","李李");
String kv1 = kv.getFirst();
String kv2 = kv.getSecond();
System.out.println(kv1);
System.out.println(kv2);
}
}
class Pair<T>{
T first;
T second;
public Pair(T first, T second){
this.first = first;
this.second = second;
}
public T getFirst(){
return first;
}
public T getSecond(){
return second;
}
}
//结果
1
100
name
李李
上面例子中的就是一个泛型类,可以发现传入 Integer 时候,T 就代表 Integer 进行处理,传入 String 时候,T 就代表 String 进行处理。数据类型作为参数传入,然后通过泛型类中的代码逻辑操作数据
public class test01 {
public static void main(String[] args) {
Pair1<String, Integer> res = new Pair1<String, Integer>("age:", 12);
String res1 = res.getFirst();
Integer res2 = res.getSecond();
System.out.println(res1 + res2);
}
}
class Pair1<X, Y>{
X first;
Y second;
public Pair1(X first, Y second){
this.first = first;
this.second = second;
}
public X getFirst(){
return first;
}
public Y getSecond(){
return second;
}
}
//结果
age:12
上面例子可以发现,泛型的类型参数可以是多个,并且类型不一样
原理
底层原理其实就是使用 Object,如果一个类是泛型类,Java 编译器会将泛型代码转换为非泛型代码,也就是将类型参数 T 替换为 Object,插入必要的强制类型转换。
PS:Java 程序运行分为两个阶段,第一阶段是编译器将 Java 源代码转换为 class 文件,第二阶段是在 JVM 中运行 class 文件。而泛型是在编译期完成的,所以 JVM 执行的时候不知道泛型的事儿,运行的就是普通类的代码
public class test1 {
public static void main(String[] args) {
Pair minMax = new Pair(1, 100);
Integer min = (Integer) minMax.getFirst();
Integer max = (Integer) minMax.getSecond();
Pair kv = new Pair("age", 12);
String age = (String) kv.getFirst();
Integer num = (Integer) kv.getSecond();
System.out.println(min);
System.out.println(max);
System.out.println(age);
System.out.println(num);
}
}
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,不知道 Integer
好处
- 安全性
有可能类型搞错了,如果不使用泛型,编译期没有问题,运行期出现问题
Pair pair = new Pair("age", 212);
Integer num = (Integer) pair.getFirst();
String age = (String) pair.getSecond();
如果使用泛型
Pair<String, Integer> pair = new Pair<>("age",1);
Integer num = pair.getFirst();//有编译错误
String age = pair.getSecond();//有编译错误
- 可读性
用途
泛型类:容器类
容纳并管理多项数据的类,动态数组举例
import java.util.Arrays;
public class DynamicArray <E>{
private static final int DEFAULT_CAPACITY = 10;
private int size;
private Object[] elementData;
public DynamicArray(){
this.elementData = new Object[DEFAULT_CAPACITY];
}
private void ensureCapacity(int minCapacity){
int oldCapacity = elementData.lengt;
if(oldCapacity >= minCapacity){
return;
}
int newCapacity = oldCapacity * 2;
if(newCapacity < minCapacity){
newCapacity = minCapacity;
}
elementData = Arrays.copyOf(elementData, newCapacity);
}
public void add(E e){
ensureCapacity(size + 1);
elementData[size++] = e;
}
public E get(int index){
return (E) elementData[index];
}
public int size(){
return size;
}
public E set(int index, E element){
E oldValue = get(index);
elementData[index] = element;
return oldValue;
}
}
使用
import java.util.Random;
public class training {
public static void main(String[] args) {
DynamicArray<Double> arr = new DynamicArray<>();
Random rnd = new Random();
int size = 1 +rnd.nextInt(100);
for(int i = 0; i < size; i++){
arr.add(Math.random());
}
Double d = arr.get(rnd.nextInt(size));
System.out.println(d);
}
}
注意:泛型中可以嵌套泛型类,例如
DynamicArray<Pair<Integer, String>> arr = new DynamicArray<>();
泛型方法
首先一个方法是否是泛型,和它所在的类是否是泛型的没有任何关系,可以所在类不是泛型,而方法是泛型,也可以所在类是泛型,方法也是泛型
public static <T> int indexOf(T[] arr, T elm){
for(int i=0; i<arr.length; i++){
if(arr[i].equals(elm)){
return i;
}
}
return -1;
}
调用
indexOf(new Integer[]{1,3,5}, 10)
indexOf(new String[]{"hello","workld"}, "OK")
泛型接口
public interface Comparable<T> {
public int compareTo(T o);
}
public final class Integer extends Number implements Comparable<Integer>{
public int compareTo(Integer anotherInteger) {
return compare(this.value, anotherInteger.value);
}
//其他代码
}
private static class CaseInsensitiveComparator implements Comparator<String> {
public int compare(String s1, String s2) {
//主体代码
}
}