欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

帶大家認(rèn)識Java語法之泛型與通配符

 更新時間:2022年03月04日 15:22:37   作者:未見花聞  
使用泛型的目的是利用Java編譯機(jī)制,在編譯過程中幫我們檢測代碼中不規(guī)范的有可能導(dǎo)致程序錯誤的代碼,下面這篇文章主要給大家介紹了關(guān)于Java泛型與通配符的相關(guān)資料,需要的朋友可以參考下

??前面的話??

本篇文章帶大家認(rèn)識Java語法——泛型與通配符,泛型和通配符是一個非常抽象的概念,簡單來說,兩者都可以將類型作為“參數(shù)”進(jìn)行傳遞,不過泛型是在你知道傳入什么類型的時候使用的,而通配符是你不確定傳入什么類型的時候使用,本文將介紹泛型與通配符的使用及兩者間的區(qū)別。

題外話: 泛型與通配符是Java語法中比較難懂的兩個語法,學(xué)習(xí)泛型和通配符的主要目的是能夠看懂源碼,實(shí)際使用的不多

1.泛型

1.1泛型的用法

1.1.1泛型的概念

《Java編程思想》上有這么一句話:一般的類和方法,只能使用具體的類型: 要么是基本類型,要么是自定義的類。如果要編寫可以應(yīng)用于多種類型的代碼,這種刻板的限制對代碼的束縛就會很大。

所以從Java5開始引入了泛型機(jī)制,這個泛型是什么意思呢?由于一般的類和方法只能使用一種具體得類型,這就使代碼受到了很大的束縛,比如一個求三個數(shù)中最大值的方法,假設(shè)一開始方法中的參數(shù)列表的類型是Integer,你從三個整型數(shù)據(jù)中找出一個最大值沒有任何問題,這個程序能夠完美地運(yùn)行,但是你要找三個浮點(diǎn)數(shù)中的最大值時,這個程序編譯都通不過,這時你可以選擇另寫一個重載方法將參數(shù)列表和實(shí)現(xiàn)功能都基于Double再實(shí)現(xiàn)一遍,這樣也可以解決問題,但是,你想過一個問題沒有,萬一有一萬甚至一百萬種類型需要求三個對象中最大那一個,那應(yīng)該怎么辦,寫一百萬個重載方法?這是不可能的,為了解決這種類型的問題,引入了泛型,泛型實(shí)現(xiàn)了參數(shù)化類型的概念,使代碼可以應(yīng)用多種類型,通俗說泛型就是“適用于許多許多類型”的意思。 使用泛型可以將類型作為“參數(shù)”傳遞至類,接口,方法中,這樣類和方法就可以具有最廣泛的表達(dá)能力,不需要因?yàn)橐粋€參數(shù)不同而去另建類型。

注意:任意的基本類型都不能作為類型參數(shù)。

1.1.2泛型類

我們通過一段代碼來認(rèn)識泛型,首先看下面一段不使用代碼的泛型的代碼:

/**
 * 不使用泛型
 */
class A {
}
class Print {
    private A a;

    public Print(A a) {
        setA(a);
        System.out.println(this.a);
    }
    public void setA(A a) {
        this.a = a;
    }
    public A getA() {
        return this.a;
    }
}

public class Generic {
   public static void main(String[] args) {
        Print print = new Print(new A());
    }
}
//output:A@1b6d3586

不使用泛型取創(chuàng)建一個類沒有任何問題,但是這個類的重用性就不怎么樣了,它只能持有類A的對象,不能持有其他任何類的對象,我們不希望為碰到的每種類型都編寫成一個新的類,這是不現(xiàn)實(shí)的。我們學(xué)習(xí)類的時候,知道Object類是所有類的父類,所以O(shè)bject類可以接受所有的類型引用,我們可以讓Print類持有Object類型的對象。

/**
 * 使用Object類
 */
class B{ }
class Print1 {
    private Object b;

    public Print1(Object b) {
        setB(b);
        System.out.println(this.b);
    }

    public void print(Object b) {
        setB(b);
        System.out.println(this.b);
    }
    
    public void setB(Object b) {
        this.b = b;
    }
}
public class Generic1 {
    public static void main(String[] args) {
        Print1 print1 = new Print1(new B());//打印B類型
        int i = 2022;
        print1.print(i);//打印整型類型
        print1.print("這是一個字符串對象!");//打印字符串類型
    }
}
//output:
//B@1b6d3586
//2022
//這是一個字符串對象!

Print1可以接收并打印任何類型,但是這并不是我們想要的結(jié)果,你想想如果實(shí)現(xiàn)的是一個順序表類,里面是通過一個數(shù)組來實(shí)現(xiàn),如果這個數(shù)組什么類型都可以接收,那就非常混亂了,取出數(shù)據(jù)的時候不能確定取出的到底是什么類型的數(shù)據(jù),而且取出的數(shù)據(jù)是Object類,需要進(jìn)行強(qiáng)制類型轉(zhuǎn)換,那能不能實(shí)現(xiàn)指定類持有什么類型的對象并且編譯器能夠檢查類型的正確性。

泛型就完美實(shí)現(xiàn)了這個目的,下面我們將上述代碼改寫成泛型類,那么首先得知道泛型的語法,泛型類創(chuàng)建語法如下:

class 類名<泛型參數(shù)列表> {
    權(quán)限修飾 泛型參數(shù) 變量名;//泛型成員變量
    權(quán)限修飾 返回值類型 方法名 (參數(shù)列表){}//參數(shù)列表和返回值類型可以是泛型
}

例如:

class Print2<T> {
    private T c;

    public void print(T c) {
        setC(c);
        System.out.println(this.c);
    }

    public void setC(T c) {
        this.c = c;
    }
}

泛型類的使用語法如下:

泛型類<類型實(shí)參> 變量名; // 定義一個泛型類引用 
new 泛型類<類型實(shí)參>(構(gòu)造方法實(shí)參); // 實(shí)例化一個泛型類對象

例如:

Print2<Integer> print3 = new Print2<Integer>();

使用泛型實(shí)現(xiàn)一個類,并使用它:

/**
 * 使用泛型
 */
class C{ }
class Print2<T> {
    private T c;

    public void print(T c) {
        setC(c);
        System.out.println(this.c);
    }

    public void setC(T c) {
        this.c = c;
    }
}
public class Generic2{
    public static void main(String[] args) {
        Print2<C> print2 = new Print2<>();//打印C類型
        print2.print(new C());
        Print2<Integer> print3 = new Print2<>();//打印整型類型
        print3.print(2022);
        Print2<String> print4 = new Print2<>();//打印字符串類型
        print4.print("這是一個字符串對象!");
    }
}
/**
 * output:
 *C@1b6d3586
 * 2022
 * 這是一個字符串對象!
 */

類名后的 <T>代表占位符,表示當(dāng)前類是一個泛型類。

【規(guī)范】類型形參一般使用一個大寫字母表示,常用的名稱有:

E 表示 Element

K 表示 Key

V 表示 Value

N 表示 Number

T 表示 Type

S, U, V 等等 - 第二、第三、第四個類型

//一個泛型類
class ClassName<T1, T2, ..., Tn> { }

使用泛型類時,指定了這個類的對象持有的類型,則該對象只能接收該類型的對象,傳入其他類型對象,編譯器會報錯,并且接收泛型類中泛型方法的返回值時,不需要進(jìn)行強(qiáng)制類型轉(zhuǎn)換(向下轉(zhuǎn)型),而使用Object類需要強(qiáng)制類型轉(zhuǎn)換。

1.1.3類型推導(dǎo)

使用泛型類時,可以通過泛型類型中傳入的類型來推導(dǎo)實(shí)例化該泛型類時所需的類型參數(shù),換個說法,定義泛型對象時,前面的尖括號內(nèi)必須指定類型,后面實(shí)例化時可以不指定。

如:

Print2<Integer> print3 = new Print2<>();//后面尖括號內(nèi)可省略

1.2裸類型

裸類型其實(shí)很好理解,就是一個泛型類,你不去指定泛型對象持有的類型,這樣的一個類型就是裸類型。

比如:

    public static void main(String[] args) {
        Print2 print2 = new Print2();
        print2.print(2022);
        print2.print("字符串");
    }
    //output:
    //2022
	//字符串

我們不要自己去使用裸類型,裸類型是為了兼容老版本的 API 保留的機(jī)制。

1.3擦除機(jī)制

1.3.1關(guān)于泛型數(shù)組

介紹泛型的擦除機(jī)制之前,我們先來了解泛型數(shù)組·,先說結(jié)論,在Java中不允許實(shí)例化泛型數(shù)組,如果一定要建立一個泛型數(shù)組,正確的做法只能通過反射來實(shí)現(xiàn),當(dāng)然有一個“捷徑”可以不使用反射來創(chuàng)建泛型數(shù)組。創(chuàng)建的代碼如下:

1.通過捷徑創(chuàng)建,大部分情況下不會出錯。

public class MyArrayList<T> {
    public T[] elem ;
    private int usedSize;

    public MyArrayList(int capacity) {
        this.elem = (T[])new Object[capacity];
    }
}

2.通過反射創(chuàng)建,現(xiàn)在只給代碼,具體為什么要這么做后續(xù)介紹反射再說。

public class MyArrayList<T> {
    public T[] elem ;
    private int usedSize;
    
    public MyArrayList(Class<T> clazz, int capacity) { 
        this.elem = (T[]) Array.newInstance(clazz, capacity); 
    }
}

1.3.2泛型的編譯與擦除

我們先來實(shí)現(xiàn)一個簡單的泛型順序表,不考慮擴(kuò)容問題,只實(shí)現(xiàn)簡單的增刪操作,來看看構(gòu)造方法部分編譯后的反匯編。

import java.lang.reflect.Array;

public class MyArrayList<T> {
    public T[] elem ;
    private int usedSize;

    public MyArrayList(int capacity) {
        this.elem = (T[])new Object[capacity];
    }
    public MyArrayList(Class<T> clazz, int capacity) {
        this.elem = (T[]) Array.newInstance(clazz, capacity);
    }
}

1-3

我們發(fā)現(xiàn)所有的泛型占位符T都被擦除替換成Object了,這就說明Java的泛型機(jī)制是在編譯期實(shí)現(xiàn)的,而泛型機(jī)制實(shí)現(xiàn)就是通過像這樣的擦除機(jī)制實(shí)現(xiàn)的,并在編譯期間完成類型的檢查。

我們通過打印持有不同類型的MyArrayList類來看看,泛型機(jī)制到底是不是不會出現(xiàn)在運(yùn)行期間,如果是的話,打印出的類型都應(yīng)該是MyArrayList。

    public static void main(String[] args) {
        MyArrayList<Integer> list1 = new MyArrayList<>(10);
        MyArrayList<String> list2 = new MyArrayList<>(10);

        System.out.println(list1);
        System.out.println(list2);
    }
    /**
     * output:
     * MyArrayList@1b6d3586
     * MyArrayList@4554617c
     */

我們發(fā)現(xiàn)打印的類型是一樣的,都是MyArrayList,所以可以得出一個結(jié)論,泛型是發(fā)生在編譯期,泛型的類型檢查是在編譯期完成的,泛型的實(shí)現(xiàn)是通過擦除機(jī)制實(shí)現(xiàn)的,類后面的占位符都會被擦除,其他的占位符都會被替換成Object。當(dāng)然,這是在泛型參數(shù)沒有指定上界的情況下,如果存在上界,那占位符會擦除成上界的類型或接口,其實(shí)沒有指定上界,上界默認(rèn)為Object,什么是泛型上界,噓,等一下再說。

根據(jù)擦除機(jī)制,也能解釋為什么Java當(dāng)中不能實(shí)例化泛型數(shù)組了,因?yàn)榉盒蛿?shù)組前面的占位符會被擦除成Object,實(shí)際上是創(chuàng)建一個Object數(shù)組,而Object數(shù)組中什么類型都能放,這就導(dǎo)致取數(shù)據(jù)時不安全,因?yàn)槟悴荒艽_定數(shù)組里面存放的元素全部都是你預(yù)期的類型,所以為了安全,Java不允許實(shí)例化泛型數(shù)組。

1.4泛型的上界

1.4.1泛型的上界

在定義泛型類時,有時需要對傳入的類型變量做一定的約束,可以通過類型邊界來約束。

class 泛型類名稱<類型形參 extends 類型邊界> {
    ...
}

例如:Number是Integer,Float,Double等相關(guān)數(shù)字類型的父類。

public class MyArrayList<T extends Number> {
	
}

那么這個MyArrayList泛型類只能指定持有Number類以及Number的子類,像這樣就給泛型的類型傳參做了約束,這個約束就是泛型的上界,泛型類被類型邊界約束時,只能指定泛型類持有類型邊界這個類及其子類。

        MyArrayList<Integer> list1 = new MyArrayList<>(10);//正確
        MyArrayList<Double> list2 = new MyArrayList<>(10);//正確
        MyArrayList<String> list3 = new MyArrayList<>(10);//錯誤,因?yàn)镾tring不是Number的子類

1.4.2特殊的泛型上界

假設(shè)需要設(shè)計一個泛型類,能夠找出數(shù)組中最大的元素。

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

由于引用類型的比較需要使用Comparable接口來判斷大小,所以所傳入的類需要實(shí)現(xiàn)Comparable接口,上面這個泛型的類型參數(shù)的上界是一個特殊的上界,表示所傳入的類型必須實(shí)現(xiàn)Comparable接口,不過實(shí)現(xiàn)了Comparable接口的類,那也就是Comparable的子類了,綜上,像這樣類似需要通過實(shí)現(xiàn)某一個接口來達(dá)到預(yù)期功能的類型,使用泛型時需指定泛型的上界,并且該傳入的類型必須實(shí)現(xiàn)該上界接口。

1.4.3泛型方法

有泛型類,那么就一定有泛型接口,泛型方法,其中泛型接口與泛型類的創(chuàng)建和使用是一樣的,所以我們重點(diǎn)介紹泛型方法的創(chuàng)建與使用。
創(chuàng)建泛型方法的基本語法:

方法限定符 <類型形參列表> 返回值類型 方法名稱(形參列表) { ... }

例如上面實(shí)現(xiàn)求數(shù)組中最大元素泛型版的方法如下:

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

對于非static修飾的靜態(tài)方法, <類型形參列表>可以省略,上述代碼可以變成:

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

但是,如果是一個static修飾的靜態(tài)方法,<類型形參列表>不可以省略,因?yàn)殪o態(tài)方法不依賴與對象,它的使用不用實(shí)例化對象,所以必須有單獨(dú)的類型參數(shù)列表來指定持有的對象類型。

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

1.4.4類型推導(dǎo)

和泛型類一樣,泛型方法也有類型推導(dǎo)的機(jī)制,如果不使用類型推導(dǎo),那么泛型方法是這么使用的:

1-4

使用類型推導(dǎo)圖中畫圓圈部分可以省略。

1-5

在泛型類中沒有如下的父子類關(guān)系:

public class MyArrayList<E> { ... }
 // MyArrayList<Object> 不是 MyArrayList<Number> 的父類型 
 // MyArrayList<Number> 也不是 MyArrayList<Integer> 的父類型

但是使用通配符這兩種類是有符子類關(guān)系的。

2.通配符

2.1通配符的概念

?就是一個通配符,用與泛型的使用,與泛型不同的是,泛型T是確定的類型,傳入類型實(shí)參后,它就確定下來了,而通配符更像是一種規(guī)定,規(guī)定一個范圍,表示你能夠傳哪些參數(shù)。

一個泛型類名尖括號之內(nèi)僅含有一個?,就會限制這個泛型類傳入的類型為Object,相當(dāng)于沒有限制,但是獲取元素時由于不能確定具體類型,只能使用Object引用接收,所以<?>也被稱為無界通配符。

    //使用泛型打印順序表
    public static<T> void printList1(ArrayList<T> list) {
        for (T x:list) {
            System.out.println(x);
        }
    }
    //使用通配符打印順序表
    public static void printList2(ArrayList<?> list) { 
        for (Object x:list) { 
            System.out.println(x); 
        }
    }

使用泛型T能夠確定傳入的類型就是T類型,所以使用T類型的變量接收,而通配符?沒有設(shè)置邊界的情況下,默認(rèn)上界是Object沒有下界,為了保證安全,只能使用Object類型的變量接收。

通配符是用來解決泛型無法協(xié)變的問題的,協(xié)變指的就是如果Student是Person的子類,那么List<Student>也應(yīng)該是List<Person>的子類。但是泛型是不支持這樣的父子類關(guān)系的。

2.2通配符的上界

通配符也有上界,可以限制傳入的類型必須是上界這個類或者是這個類的子類。

基本語法:

<? extends 上界> 
<? extends Number>//可以傳入的實(shí)參類型是Number或者Number的子類

例如:

    public static void printAll(ArrayList<? extends Number> list) {
        for (Number n: list) {
            System.out.println(n);
        }
    }

我們對printAll方法的一個形參限制了類型的上界Number,所以在遍歷這個順序表的時候,需要使用Number來接收順序表中的對象,并且使用該方法時,只能遍歷輸出Number及其子類的對象。

    public static void main(String[] args) {
        printAll(new ArrayList<Integer>());//ok
        printAll(new ArrayList<Double>());//ok
        printAll(new ArrayList<Float>());//ok

        printAll(new ArrayList<String>());//error
    }

2-2

假設(shè)有如下幾個類:

class Animal{}
class Cat extends Animal{}
class Dog extends Animal{}
class Bird extends Animal{}

Animal是Cat,Dog,Bird類的父類,我們來看一看使用泛型和使用通配符在打印對象結(jié)果上會有什么區(qū)別?我們對這兩者都設(shè)置了上界,當(dāng)打印不同的對象時,到底會調(diào)用誰的toString方法。

	//泛型
    public static <T extends Animal> void printAnimal1(ArrayList<T> list) {
        for (T animal: list) {
            System.out.println(animal);
        }
    }
    //通配符
        public static void printAnimal2(ArrayList<? extends Animal> list) {
        for (Animal animal: list) {
            System.out.println(animal);
        }
    }

我們先來看泛型,使用泛型指定類型后,那么指定什么類型,那它就會輸出什么類型的對象,比如你指定順序表中放的類型是Cat,那么它調(diào)用的就是Cat對象的toString方法。

    public static void main(String[] args) {
        Cat cat = new Cat();
        Dog dog = new Dog();
        Bird bird = new Bird();

        //泛型
        ArrayList<Cat> list1 = new ArrayList<>();
        ArrayList<Dog> list2 = new ArrayList<>();
        ArrayList<Bird> list3 = new ArrayList<>();
        list1.add(cat);
        list2.add(dog);
        list3.add(bird);
        printAnimal1(list1);//Cat
        printAnimal1(list2);//Dog
        printAnimal1(list3);//Bird
    }

2-4

再來看一看通配符,使用通配符是規(guī)定能夠使用Animal及其子類,不倫你傳入哪一個子類對象,都是父類的引用接收,但是具體哪一個子類,并不清楚。

    public static void main(String[] args) {
        Cat cat = new Cat();
        Dog dog = new Dog();
        Bird bird = new Bird();

        //通配符
        ArrayList<Cat> list1 = new ArrayList<>();
        ArrayList<Dog> list2 = new ArrayList<>();
        ArrayList<Bird> list3 = new ArrayList<>();
        list1.add(cat);
        list2.add(dog);
        list3.add(bird);
        printAnimal2(list1);//Cat
        printAnimal2(list2);//Dog
        printAnimal2(list3);//Bird
    }

2-5

父類引用接收子類對象發(fā)生了向上轉(zhuǎn)型,當(dāng)打印父類引用的子類對象時,會優(yōu)先使用子類的toString方法,在介紹多態(tài)的時候也講過這個問題,所以輸出結(jié)果與使用泛型是一樣的,但是泛型和通配符的效果是不一樣的,泛型是你傳入什么類型,那這個類就會持有什么類型的對象,而通配符是規(guī)定一個范圍,規(guī)定你能夠傳哪一些類型。

通配符的上界是支持如下的父子類關(guān)系的,而泛型的上界不支持:

MyArrayList<? extends Number> 是 MyArrayList <Integer>或者 MyArrayList<Double>的父類類型 
MyArrayList<?> 是 MyArrayList<? extends Number> 的父類型

對于通配符的上界有個特點(diǎn),先說結(jié)論,使用通配符上界可以讀取數(shù)據(jù),但是并不適合寫入數(shù)據(jù),因?yàn)椴荒艽_定類所持有的對象具體是什么。

    public static void main(String[] args) {
        ArrayList<Integer> arrayList1 = new ArrayList<>();
        ArrayList<Double> arrayList2 = new ArrayList<>();
        arrayList1.add(10);
        List<? extends Number> list = arrayList1;
        System.out.println(list.get(0));//ok
        Integer = list.get(0);//error因?yàn)椴荒艽_定list所持有的對象具體是什么
        list.add(2);//error因?yàn)椴荒艽_定list所持有的對象具體是什么,為了安全,這種情況Java不允許插入元素
    }

2-6

因?yàn)閺膌ist獲取的對象類型一定Number或者Number的子類,所以可以使用Number引用來獲取元素,但是插入元素時你并不能確定它到底是哪一種類型,為了安全,使用通配符上界的list不允許插入元素。

2.3通配符的下界

與泛型不同,通配符可以擁有下界,語法層面上與通配符的上界的區(qū)別是講關(guān)鍵字extends改為super。

<? super 下界> 
<? super Integer>//代表 可以傳入的實(shí)參的類型是Integer或者Integer的父類類型

既然是下界那么通配符下界與上界對傳入類的規(guī)定是相反的,即規(guī)定一個泛型類只能傳入下界的這個類類型或者這個類的父類類型。比如<? super Integer>代表 可以傳入的實(shí)參的類型是Integer或者Integer的父類類型(如Number,Object)

    public static void printAll(ArrayList<? super Number> list) {
        for (Object n: list) {			//此處只能使用Object接收,因?yàn)閭魅氲念愂荖umber或者是Number的父類
            System.out.println(n);
        }
    }
    public static void main(String[] args) {
        printAll(new ArrayList<Number>());//ok
        printAll(new ArrayList<Object>());//ok

        printAll(new ArrayList<Double>());//error
        printAll(new ArrayList<String>());//error
        printAll(new ArrayList<Integer>());//error
    }

2-7

同理通配符的下界也是滿足像下面這種父子類關(guān)系的。

MyArrayList<? super Integer> 是 MyArrayList<Integer>的父類類型 
MyArrayList<?> 是 MyArrayList<? super Integer>的父類類型

總結(jié):

?是? extends ....和? super ....的父類,看通配符之間的父子類關(guān)系,最關(guān)鍵的是看通配符所“規(guī)定的”范圍,判斷父子類是根據(jù)這個范圍來判斷的。

通配符的下界也有一個特點(diǎn),那就是它能夠允許寫入數(shù)據(jù),當(dāng)然能夠?qū)懭氲臄?shù)據(jù)對象是下界以及下界的子類,但是并不擅長讀數(shù)據(jù),與通配符的上界相反。

    public static void main(String[] args) {
        ArrayList<? super Animal> list = new ArrayList<Animal>(); 
        ArrayList<? super Animal> list2 = new ArrayList<Cat>();//編譯報錯,list2只能引用Animal或者Animal父類類型的list
        list.add(new Animal());//添加元素時,只要添加的元素的類型是Animal或者Animal的子類就可以
        list.add(new Cat());
        Object s2 = list.get(0);//可以
        
        ArrayList<? super Animal> list3 = new ArrayList<Object>();
        Cat s1 = list3.get(0);//error因?yàn)闃?gòu)造對象時可以構(gòu)造Animal父類類型的ArrayList,取出的對象不一定是Animal或者Animal的子類
    }

2-8

對于這個栗子添加元素時,只要添加的元素的類型是Animal或者Animal的子類就可以,獲取元素時,只能使用Object引用接收,不能使用其他的引用接收,因?yàn)橐驗(yàn)闃?gòu)造對象時可以構(gòu)造Animal父類類型的ArrayList,雖然可以插入Animal以及其子類對象,但取出的對象不能保證是Animal或者Animal的子類。

關(guān)于泛型和通配符就介紹到這里了,這兩個概念是非常抽象而且難懂的,而且用的也不多,因?yàn)榛旧弦院竽阋矝]機(jī)會用了,因?yàn)榉盒屯ㄅ浞诰帉戭愃艼ava或者其他語言源碼的時候才用得到,學(xué)習(xí)泛型通配符的主要目的是能夠讀懂源碼,看得懂其他人寫的代碼。

哎!寫關(guān)于java語法的用法的時候真的是一頭霧水??!

總結(jié)

到此這篇關(guān)于Java泛型與通配符的文章就介紹到這了,更多相關(guān)Java泛型與通配符內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • spring Data jpa簡介_動力節(jié)點(diǎn)Java學(xué)院整理

    spring Data jpa簡介_動力節(jié)點(diǎn)Java學(xué)院整理

    這篇文章主要介紹了spring Data jpa簡介的相關(guān)資料,需要的朋友可以參考下
    2017-09-09
  • Java的BigDecimal在math包中提供的API類場景使用詳解

    Java的BigDecimal在math包中提供的API類場景使用詳解

    這篇文章主要介紹了Java的BigDecimal在math包中提供的API類場景使用詳解,BigDecimal,用來對超過16位有效位的數(shù)進(jìn)行精確的運(yùn)算,雙精度浮點(diǎn)型變量double可以處理16位有效數(shù),在實(shí)際應(yīng)用中,需要對更大或者更小的數(shù)進(jìn)行運(yùn)算和處理,需要的朋友可以參考下
    2023-12-12
  • java中extends與implements的區(qū)別淺談

    java中extends與implements的區(qū)別淺談

    java中extends與implements的區(qū)別淺談,需要的朋友可以參考一下
    2013-03-03
  • Java中LinkedList的模擬實(shí)現(xiàn)

    Java中LinkedList的模擬實(shí)現(xiàn)

    本文主要介紹了Java中LinkedList的模擬實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-06-06
  • JAVA語法糖原理你知道嗎

    JAVA語法糖原理你知道嗎

    語法糖(Syntactic sugar),也叫做糖衣語法,是英國科學(xué)家發(fā)明的一個術(shù)語,通常來說使用語法糖能夠增加程序的可讀性,從而減少程序代碼出錯的機(jī)會.這篇文章主要介紹了Java 中的語法糖知識,需要的朋友可以參考下
    2021-09-09
  • springboot排除某些自動配置的操作方法

    springboot排除某些自動配置的操作方法

    Spring Boot 提供的自動配置非常強(qiáng)大,某些情況下,自動配置的功能可能不符合我們的需求,需要我們自定義配置,這個時候就需要排除/禁用Spring Boot 某些類的自動化配置了,本文給大家介紹springboot排除某些自動配置的方法,感興趣的朋友一起看看吧
    2023-08-08
  • Spring集成MyBatis框架

    Spring集成MyBatis框架

    本文主要介紹了Spring集成MyBatis的配置和使用,項目基于Maven構(gòu)建,連接Mysql數(shù)據(jù)庫。下面跟著小編一起來看下吧
    2017-02-02
  • springboot 打包部署 共享依賴包(分布式開發(fā)集中式部署微服務(wù))

    springboot 打包部署 共享依賴包(分布式開發(fā)集中式部署微服務(wù))

    這篇文章主要介紹了springboot 打包部署 共享依賴包(分布式開發(fā)集中式部署微服務(wù))的相關(guān)資料,非常不錯,具有參考借鑒價值,需要的的朋友參考下吧
    2017-06-06
  • java異常處理執(zhí)行順序詳解try catch finally

    java異常處理執(zhí)行順序詳解try catch finally

    try catch語句是java語言用于捕獲異常并進(jìn)行處理的標(biāo)準(zhǔn)方式,對于try catch及try catch finally執(zhí)行順序必須有深入的了解
    2021-10-10
  • Java如何將字符串String轉(zhuǎn)換為整型Int

    Java如何將字符串String轉(zhuǎn)換為整型Int

    這篇文章主要介紹了Java如何將字符串String轉(zhuǎn)換為整型Int,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價值,需要的朋友可以參考一下
    2022-08-08

最新評論