天天看点

666之Java泛型的思考

近来重温了一下《Core Java》中的第8章,关于泛型的描述,重拾了一下之前的知识和理解,总结几点思考和感悟如下:

  • 泛型的声明

在类或者方法的定义过程中,可以进行泛型的声明(一般用大写字母T来表示),以便类或者方法的后续编写过程中可以使用这个T作为特定类的表示。

  • 泛型在类定义时的声明

public class Pair<T> {
    private T first;
    private T second;

    public T getFirst(){}
    public T getSecond(){}
    public void setFirst(T first){
        this.first = first;
    }
    public void setSecond(T second){
        this.second = second;
    }
}
           

跟在Pair后在尖括号中的T就是类定义中泛型的声明。

  • 泛型在方法定义时的声明

类似的,方法定义过程中也可以进行泛型的声明,一般是在方法的modifiers后返回值前。

public class MethodGeneric{
    public static <T> T printAndReturn(T t){
        System.out.println("do nothing then return input parameter.");
        return t;
    }
}
           

值得注意的有2点:

注意点1,泛型类型可以继承1个类并同时实现若干个接口,均用关键字extends来表示,继承的父类(仅能继承1个)必须放在extends后第一位,实现多个接口用&连接起来,如下代码所示:

public class GenericExtends<T extends BaseClass & Comparable & Serializable> {
    //class body
}
           

注意点2,泛型T是一种编译时的概念,而不是运行时的概念。也就是说在Java虚拟机运行时是没有泛型的概念的,统一为Object类或者泛型T所继承的类或者实现的接口(一般替换为声明时extends后的第一个)。编译时会在必要的return等地方根据使用泛型时传入的具体类型做强制类型转换。

  • 泛型的上界和下界

说到泛型的上界和下界,必须提到通配符(wildcard——”?“)。为了方便说明,我们定义两个类:父类Father和子类Son,以及泛型类Pair。

public class Pair<T> {
    private T first;
    private T second;

    public T getFirst(){}
    public T getSecond(){}
    public void setFirst(T first){
        this.first = first;
    }
    public void setSecond(T second){
        this.second = second;
    }
}

class Father{}
class Son extends Father{}
           

首先是泛型的上界,例如? extends Father,这里需要特别注意的是此处是使用泛型时这个具体传给T的类型必须是Father的子类。使用上界时可以用get方法,而无法使用set方法,这个具体该怎么理解呢,我们看一下的案例

public static void main(String[] args){
    
    Pair<? extends Father> p = new Pair<>();
    p.getFirst();    //OK
    Son s = p.getFirst();   //Error,T为Fahter的子类,因此getFirst()可能回传Father或者Son,因此不能用Son来接收,只能用Father来接收。
    Father f = p.getFirst();    //OK

    p.setFiert(new Father());    
    //Error,因为此时Pair中的类型T是必须是Father的子类,但是并不知道具体是哪一个子类,究竟是Father还是Son,不明确,所以无法传具体的类型给T。

}