1. 程式人生 > 其它 >Java泛型中 extends和super

Java泛型中 extends和super

Java泛型中的extends和super理解


在平時看原始碼的時候我們經常看到泛型,且經常會看到extends和super的使用,看過其他的文章裡也有講到上界萬用字元和下屆萬用字元,總感覺講的不夠明白。這裡備註一下,以免忘記。

extends也稱為上界萬用字元,就是指定上邊界。即泛型中的類必須為當前類的子類或當前類。
super也稱為下屆萬用字元,就是指定下邊界。即泛型中的類必須為當前類或者其父類。
這兩點不難理解,extends修飾的只能取,不能放,這是為什麼呢?

先看一個列子:

public class Food {}
public class Fruit extends Food {}
public class Apple extends Fruit {}
public class Banana extends Fruit{}

public class GenericTest {

public void testExtends(List<? extends Fruit> list){

//報錯,extends為上界萬用字元,只能取值,不能放.
//因為Fruit的子類不只有Apple還有Banana,這裡不能確定具體的泛型到底是Apple還是Banana,所以放入任何一種型別都會報錯
//list.add(new Apple());

//可以正常獲取
Fruit fruit = list.get(1);
}

public void testSuper(List<? super Fruit> list){

//super為下界萬用字元,可以存放元素,但是也只能存放當前類或者子類的例項,以當前的例子來講,
//無法確定Fruit的父類是否只有Food一個(Object是超級父類)
//因此放入Food的例項編譯不通過
list.add(new Apple());
// list.add(new Food());

Object object = list.get(1);
}

在testExtends方法中,因為泛型中用的是extends,在向list中存放元素的時候,我們並不能確定List中的元素的具體型別,即可能是Apple也可能是Banana。因此呼叫add方法時,不論傳入new Apple()還是new Banana(),都會出現編譯錯誤。

理解了extends之後,再看super就很容易理解了,即我們不能確定testSuper方法的引數中的泛型是Fruit的哪個父類,因此在呼叫get方法時只能返回Object型別。結合extends可見,在獲取泛型元素時,使用extends獲取到的是泛型中的上邊界的型別(本例子中為Fruit),範圍更小。

總結:
在使用泛型時,存取元素時用super,獲取元素時,用extends
————————————————

package com.Iori;

import android.app.Activity;

import com.Iori.Util.CommUtil;

import java.lang.ref.WeakReference;

import com.Iori.IEntity;
import androidx.annotation.Nullable;

public abstract class CommonCallback<T extends IEntity> extends GeneralCallback<T>
{
    protected Activity __this;
    public CommonCallback()
    {
        __this = (Activity) getWeakRefActivity().get();
    }

    private boolean checkContent()
    {
        Activity activity = (Activity) getWeakRefActivity().get();
        if(activity == null || activity.isFinishing())
        {
            return false;
        }
        return true;
    }

    protected boolean isDismissLoadingDataReady()
    {
        return true;
    }

    @Override
    public void onDataReady(@Nullable T data)
    {
        if(checkContent() == false) return;
        if(isDismissLoadingDataReady())
        {
            CommUtil.dismissHUD();
        }
        if(data.Success)
        {
            doProcessData(data);
        }
        else
        {
            CommUtil.alert(
                    __this,
                    null,
                    data.Msg);
        }
    }

    public abstract void doProcessData(T data);
}