java泛型

基本概念

一个简单的泛型类

public 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;
    }
}

pair就是一个泛型类,与普通的类的区别体现在一下两点:

  1. 类名后面多了一个
  2. firstsecond的类型都是T

上面的T就是类型参数,所谓的泛型其实就是类型参数化,处理的数据类型不是固定的,而是可以作为参数传入的。

比如此时使用Integer来实例化Pair,代码如下:

Pair<Integer> minmax = new Pair<Integer>(1, 100);
Integer min = minmax.getFirst();
Integer max = minmax.getSecond();

上面的Integer就是传递的实际参数类型。

如果传入的是String的话:

Pair<String> minmax = new Pair<String>("name", "张三");

传入的类型不同,处理的类型也就不一样,所以说Pair类的代码和它处理的数据类型不是绑定的,类型是可变的。

类型参数可以是多个

public class Pair<U, V> {
    U first;
    V second;
    public Pair(U first, V second){
        this.first = first;
        this.second = second;
    }
    public U getFirst() {
    	return first;
    }
    public V getSecond() {
    	return second;
    }
}

上面的例子中就是有不同的参数类型。

获取该类对象:

Pair<String,Integer> pair = new Pair<String,Integer>("字符串",100);

java7开始,new后面的类型可以不用写:

Pair<String,Integer> pair = new Pair<>("字符串",100);

实现原理

先看一下下面的代码

public 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;
    }
}

上面的代码其实就是泛型的实现机制。将原理之前先要明白java的两个知识点:

  • java编译器
    编译器的作用是将源代码转换为.class文件,对于泛型类,java编译器会将泛型代码转换为普通的非泛型代码(就像上面代码一样,其实就是替换为Object,然后进行强制类型转换),这一步叫做擦除类型参数。
  • java虚拟机
    虚拟机的的作用是加载并运行.class文件。对于泛型类,在上面的编译器阶段就已经擦除了类型参数,所以在程序运行阶段是不知道泛型的实际类型参数的,比如说Pair<Integer>,在程序运行时候只是知道Pair,不知道Integer的。

使用泛型的好处

既然泛型的实现原理就是使用Object,那么为什么不直接使用Object,而是要使用泛型呢,主要是有一下两个好处:

  • 更好的安全性
    使用Object是需要进行强制转换到需要的类型的,但是使用Object时在编译的时候如果转换错误也是不会提醒的,只要在运行的时候才会报ClassCastException,但是使用泛型如果转换错误在编译阶段就会发现。
  • 更好的可读性

泛型的类别

泛型类(容器类)

上面的那个例子就是一个泛型类,对于泛型类一般是用作容器类,比如ArrayList类就是一个泛型类,同时也是一个泛型类。

泛型方法

除了泛型类还可以有泛型方法,而且一个方法是不是泛型的,与其所在的类是不是泛型没有关系。

一个参数的泛型方法

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","测试1", "name")

多个参数的泛型方法

public static <U,V> Pair<U,V> makePair(U first, V second){
	Pair<U,V> pair = new Pair<>(first, second);
 	return pair;
}
多个参数的泛型方法的调用
makePair(1,"名称");

注:与泛型类不同,调用方法时一般不需要特意指定类型参数的实际类型,java编译器可以自己推断出来。

泛型方法的格式

从上面泛型方法的案例可以看到泛型方法的格式是:

  • 对于普通类型,类型参数放在返回值前面
  • 对于自定义类型,除了在返回值前面加上类型参数,还需要在类后面也加上类型参数,比如上面的多个参数的方法那个案例。

泛型接口

接口定义时使用泛型

比如Comparable接口就是泛型的。

public interface Comparable<T> {
	public int compareTo(T o);
}

实现泛型接口需指定类型

接口的定义使用的是泛型,但是在实现接口时需要指定具体的类型。比如使用Integer类实现上面的接口:

public final class Integer extends Number implements 	Comparable<Integer>{
    public int compareTo(Integer anotherInteger) {
        return compare(this.value, anotherInteger.value);
    }
}

类型参数的限定

在前面讲过泛型的本质是通过使用Object,不过java还支持限定这个参数的上界。

上限为某一个类

最开始那个pair类的代码:

public 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;
    }
}

假设该类有一个子类。并且需要限定两个参数的类型为Number

public class NumberPair<U extends Number, V extends Number> extends Pair<U, V> {
	public NumberPair(U first, V second) {
    	super(first, second);
    }
}

然后就可以直接使用限定的类型的方法,而且如果类型使用错误编译时就会提示。指定边界后,类型擦除时就不会转换为Object而是转换为边界类型。

上界为某一个接口

以上界是Comparable接口为例:

编译会有警告形式

public static <T extends Comparable>T max(T[] arr){
    T max = arr[0];
    for(int i=1; i < arr.length; i++){
       if(arr[i].compareTo(max) > 0){
           max = arr[i];
       }
    }
    return max;
}

正确完整形式

public static <T extends Comparable<T>> T max(T[] arr){
 //上面的主体代码
}

<T extends Comparable<T>>这种形式称为递归类型限制。解释为:

T表示一种数据类型,必须实现Comparable接口,并且必须与形同类型的元素进行比较。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值