<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                企業??AI智能體構建引擎,智能編排和調試,一鍵部署,支持知識庫和私有化部署方案 廣告
                ### 一、泛型的理解與簡單使用 泛型是Java SE 1.5的新特性,泛型的本質是參數化類型,也就是說所操作的數據類型被指定為一個參數。這種參數類型可以用在類、接口和方法的創建中,分別稱為泛型類、泛型接口、泛型方法。 Java語言引入泛型的好處是安全簡單。 在Java SE 1.5之前,沒有泛型的情況的下,通過對類型Object的引用來實現參數的“任意化”,“任意化”帶來的缺點是要做顯式的強制類型轉換,而這種轉換是要求開發者對實際參數類型可以預知的情況下進行的。對于強制類型轉換錯誤的情況,編譯器可能不提示錯誤,在運行的時候才出現異常,這是一個安全隱患。 泛型的好處是在編譯的時候檢查類型安全,并且所有的強制轉換都是自動和隱式的,以提高代碼的重用率。 **1.1、泛型在接口上的使用:** ~~~ package com.luo.test; public interface TestInterface<T> { String objectToString(T o); } ~~~ 對應實現類可以這樣: ~~~ package com.luo.test; public class TestInterfaceImpl<T> implements TestInterface<T> { public String objectToString(T o) { return o.toString(); } public static void main(String args[]){ TestInterfaceImpl<Integer> testInterfaceImpl = new TestInterfaceImpl<Integer>(); Integer integer = new Integer(123); System.out.println(testInterfaceImpl.objectToString(integer)); } } ~~~ 運行結果:123 **1.2、泛型在類上單獨使用(不實現接口):** ~~~ package com.luo.test; public class ClassTest<T> { private T ob; // 定義泛型成員變量 public T getOb() { return ob; } public void setOb(T ob) { this.ob = ob; } public void showObType() { System.out.println("T的實際類型是: " + ob.getClass().getName()); } public static void main(String args[]){ ClassTest<Integer> classTest = new ClassTest<Integer>(); classTest.setOb(123); classTest.showObType(); } } ~~~ 運行結果:T的實際類型是: java.lang.Integer **1.3、泛型在方法上單獨使用:** 例如想要實現: ~~~ public List<String> ArrayToList(String[] array); public List<Double> ArrayToList(Double[] array); ~~~ 那么你可以使用泛型如下: ~~~ package com.luo.test; import java.util.ArrayList; import java.util.List; public class MyTest { public <T> List<T> write(T[] array){ List<T> list = new ArrayList<T>(); for (int i = 0; i < array.length; i++) { list.add(array[i]); } return list; } public static void main(String args[]){ } } ~~~ ### 二、泛型的高級使用 **2.1、通配符“?”** 先看如下代碼: ![這里寫圖片描述](https://box.kancloud.cn/2016-03-15_56e77db4b2129.jpg "") 我們都知道,Object所有類的基類,但是需要注意的是 ~~~ Collection<Object>并不是所有集合的超類。 List<Object>, List<String>是兩種不同的類型,他們之間沒有繼承關系,即使String繼承了Object。 這就是泛型的強大之處,引入范型后,一個復雜類型如(List),就可以在細分成更多的類型。 ~~~ 為解決上面代碼報錯問題,引入通配符“?”: ![這里寫圖片描述](https://box.kancloud.cn/2016-03-15_56e77db4ca881.jpg "") 這樣就不會編譯出錯啦。這里使用了通配符“?”指定可以使用任何類型的集合作為參數。 **2.2、邊界通配符“?extends”** 假定有一個畫圖的應用,可以畫各種形狀的圖形,如矩形和圓形等。為了在程序里面表示,定義如下的類層次: ~~~ public abstract class Shape { public abstract void draw(Canvas c); } public class Circle extends Shape { private int x,y,radius; public void draw(Canvas c) { ... } } public class Rectangle extends Shape private int x,y,width,height; public void draw(Canvas c) { ... } } ~~~ ~~~ 為了畫出集合中所有的形狀,我們可以定義一個函數,該函數接受帶有泛型的集合類對象作為參數。但是不幸的是,我們只能接收元素類型為Shape的List對象,而不能接收類型為List<Cycle>的對象,這在前面已經說過。為了解決這個問題,所以有了邊界通配符的概念。這里可以采用public void drawAll(List<? extends Shape> shapes)來滿足條件,這樣就可以接收元素類型為Shape子類型的列表作為參數了。 ~~~ ~~~ //使用邊界通配符的版本 public void drawAll(List<?exends Shape> shapes) { for (Shapes:shapes) { s.draw(this); } } ~~~ 這里就又有個問題要注意了,如果我們希望在List<?exends Shape> shapes中加入一個矩形對象,如下所示: shapes.add(0, new Rectangle()); //compile-time error 那么這時會出現一個編譯時錯誤,原因在于:我們只知道shapes中的元素時Shape類型的子類型,具體是什么子類型我們并不清楚,所以我們不能往shapes中加入任何類型的對象。不過我們在取出其中對象時,可以使用Shape類型來取值,因為雖然我們不知道列表中的元素類型具體是什么類型,但是我們肯定的是它一定是Shape類的子類型。 為解決添加問題,引入通配符“?super” **2.3、通配符“?super”** ~~~ List<Shape> shapes = new ArrayList<Shape>(); List<? super Cicle> cicleSupers = shapes; cicleSupers.add(new Cicle()); //OK, subclass of Cicle also OK cicleSupers.add(new Shape()); //ERROR ~~~ 這表示cicleSupers列表存儲的元素為Cicle的超類,因此我們可以往其中加入Cicle對象或者Cicle的子類對象,但是不能加入Shape對象。這里的原因在于列表cicleSupers存儲的元素類型為Cicle的超類,但是具體是Cicle的什么超類并不清楚。但是我們可以確定的是只要是Cicle或者Circle的子類,則一定是與該元素類別兼容。 **2.4、通配符總結** 如果你想從一個數據類型里獲取數據,使用 ? extends 通配符 如果你想把對象寫入一個數據結構里,使用 ? super 通配符 如果你既想存,又想取,那就別用通配符。 ### 三、總結 **3.1、 類型擦除概念** 類型擦除指的是通過類型參數合并,將泛型類型實例關聯到同一份字節碼上。編譯器只為泛型類型生成一份字節碼,并將其實例關聯到這份字節碼上,因此泛型類型中的靜態變量是所有實例共享的。此外,需要注意的是,一個static方法,無法訪問泛型類的類型參數,因為類還沒有實例化,所以,若static方法需要使用泛型能力,必須使其成為泛型方法。類型擦除的關鍵在于從泛型類型中清除類型參數的相關信息,并且再必要的時候添加類型檢查和類型轉換的方法。在使用泛型時,任何具體的類型都被擦除,唯一知道的是你在使用一個對象。比如:List和List在運行事實上是相同的類型。他們都被擦除成他們的原生類型,即List。因為編譯的時候會有類型擦除,所以不能通過同一個泛型類的實例來區分方法,如下面的例子編譯時會出錯,因為類型擦除后,兩個方法都是List類型的參數,因此并不能根據泛型類的類型來區分方法。 ~~~ /*會導致編譯時錯誤*/ public class Erasure{ public void test(List<String> ls){ System.out.println("Sting"); } public void test(List<Integer> li){ System.out.println("Integer"); } } ~~~ 那么這就有個問題了,既然在編譯的時候會在方法和類中擦除實際類型的信息,那么在返回對象時又是如何知道其具體類型的呢?如List編譯后會擦除掉String信息,那么在運行時通過迭代器返回List中的對象時,又是如何知道List中存儲的是String類型對象呢? 擦除在方法體中移除了類型信息,所以在運行時的問題就是邊界:即對象進入和離開方法的地點,這正是編譯器在編譯期執行類型檢查并插入轉型代碼的地點。泛型中的所有動作都發生在邊界處:對傳遞進來的值進行額外的編譯期檢查,并插入對傳遞出去的值的轉型。 **3.2、方法重載** 在JAVA里面方法重載是不能通過返回值類型來區分的,比如代碼一中一個類中定義兩個如下的方法是不容許的。但是當參數為泛型類型時,卻是可以的。如下面代碼二中所示,雖然形參經過類型擦除后都為List類型,但是返回類型不同,這是可以的。 ~~~ /*代碼一:編譯時錯誤*/ public class Erasure{ public void test(int i){ System.out.println("Sting"); } public int test(int i){ System.out.println("Integer"); } } ~~~ ~~~ /*代碼二:正確 */ public class Erasure{ public void test(List<String> ls){ System.out.println("Sting"); } public int test(List<Integer> li){ System.out.println("Integer"); } } ~~~ **3.3、泛型類型是被所有調用共享的** 所有泛型類的實例都共享同一個運行時類,類型參數信息會在編譯時被擦除。因此考慮如下代碼,雖然ArrayList和ArrayList類型參數不同,但是他們都共享ArrayList類,所以結果會是true。 ~~~ List<String>l1 = new ArrayList<String>(); List<Integer>l2 = new ArrayList<Integer>(); System.out.println(l1.getClass() == l2.getClass()); //True ~~~ **3.4、instanceof** 不能對確切的泛型類型使用instanceOf操作。如下面的操作是非法的,編譯時會出錯。 ~~~ Collection cs = new ArrayList<String>(); if (cs instanceof Collection<String>){…}// compile error.如果改成instanceof Collection<?>則不會出錯。 ~~~ **3.5、泛型數組問題** 不能創建一個確切泛型類型的數組。如下面代碼會出錯。 ~~~ List<String>[] lsa = new ArrayList<String>[10]; //compile error. ~~~ 因為如果可以這樣,那么考慮如下代碼,會導致運行時錯誤。 ~~~ List<String>[] lsa = new ArrayList<String>[10]; // 實際上并不允許這樣創建數組 Object o = lsa; Object[] oa = (Object[]) o; List<Integer>li = new ArrayList<Integer>(); li.add(new Integer(3)); oa[1] = li;// unsound, but passes run time store check String s = lsa[1].get(0); //run-time error - ClassCastException ~~~ 因此只能創建帶通配符的泛型數組,如下面例子所示,這回可以通過編譯,但是在倒數第二行代碼中必須顯式的轉型才行,即便如此,最后還是會拋出類型轉換異常,因為存儲在lsa中的是List<Integer>類型的對象,而不是List<String>類型。最后一行代碼是正確的,類型匹配,不會拋出異常。 ~~~ List<?>[] lsa = new List<?>[10]; // ok, array of unbounded wildcard type Object o = lsa; Object[] oa = (Object[]) o; List<Integer>li = new ArrayList<Integer>(); li.add(new Integer(3)); oa[1] = li; //correct String s = (String) lsa[1].get(0);// run time error, but cast is explicit Integer it = (Integer)lsa[1].get(0); // OK&nbsp; ~~~ 參考文章: [http://qiemengdao.iteye.com/blog/1525624](http://qiemengdao.iteye.com/blog/1525624)
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看