Java编程思想:擦除的神秘之处
生活随笔
收集整理的這篇文章主要介紹了
Java编程思想:擦除的神秘之处
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.List;public class Test {public static void main(String[] args) {
// ErasureAndInheritance.test();
// ArrayMaker.test();
FilledListMaker.test();}
}/*15.7 擦除的神秘之處Class.getTypeParameters()將返回一個TypeVariable對象數組,表示有泛型聲明所聲明的類型參數。我之前確實有過這種需求,但是這個方法不可能給我想要的結果問題:因此,你可以知道諸如類型參數標識符和泛型類型邊界這類的信息——你卻無法知道用來創建某個特定實例的實際的類型參數。Java泛型是使用擦除來實現的,這意味著當你在使用泛型的時候,任何具體的類型信息都被擦除了,你唯一知道的就是你在使用一個對象因此List<String>和List<Integer>在運行時事實上是相同的類型。這兩種類型都被擦除成了它們的“原生”類型,即List。理解擦除以及應該如何處理它,是你在學習Java泛型時面臨的最大障礙。——既然被擦除了,為什么我們還能取到我們想要的類型——C++中如果你用了泛型,編譯器就會對應的生成這個類,這一點還是蠻舒服的。*//*15.7.1 C++的方式C++:template<class T> class Manipulator{T obj;public:Manipulator(T x) { obj = x;}void manipulator() { obj.f();}}Java: 無法通過編譯class Manipulator<T>{T obj;public Manipulator(T x) { obj = x; }void manipulator() { obj.f();}}解決問題:為了調用f(),我們必須協助泛型類,給定泛型類的邊界,以此告知編譯器只能接受這個邊界的類型。這里重用了extends關鍵字<T extends HasF> : 聲明T必須具有類型HasF或者從HasF導出的類型,我們說泛型類型參數將擦除到它的第一個邊界(可能會有多個邊界)。*/
class HasF {public void f() {}
}
class Manipulator<T extends HasF>
{T obj;public Manipulator(T x) { obj = x; }void manipulator() { obj.f();}
}/*在我們的案例中,泛型沒有任何貢獻。我們完全可以自己執行泛型擦除。這一點很重要:只有當你希望使用的類型參數比某個具體類型(以及它的所有子類型)更加“泛化”時——也就是說,當你希望代碼能夠跨多個類工作時,使用泛型才有所幫助。——額,為什么不用接口呢?接口不也是這種功能么,甚至比這個還有強大一點因此,類型參數和它們在有用的泛型代碼中的應用,通常比簡單的類替換要更復雜。但是,不能因此而認為<T extends HasF>形式的任何東西都是有缺陷的。例如,如果某個類有一個返回T的方法,那么泛型就有所幫助,因此它們之后將返回確切的類型。——我想知道,既然類型已經被擦除了,那返回時是如何返回成T的了,難道是編譯器私下里進行了一次強制轉換?*//*15.7.3 擦除的問題擦除的主要的正當理由是非泛型的代碼到泛型到泛型代碼的轉變過程。擦除的代價是顯著的。泛型不能用于顯式的引用運行時類型的操作之中,例如轉型、instanceof操作和new表達式。因為所有關于參數的類型的信息都丟失了。*/class GenericBase<T>{private T element;public void set(T arg) { element = arg;}public T get(){return element;}
}class Dervied1<T> extends GenericBase<T> {}
class Dervied2 extends GenericBase {}class ErasureAndInheritance{static void test() {Dervied2 d = new Dervied2();Object obj = d.get();d.set(obj);}
}/*17.5.4 邊界處的動作*//*編譯器不會給出任何警告,盡管我們從擦除中知道在create()內部的new ArrayList<T>中的<T>被移除了——在運行時,這個類的內部沒有任何的<T>。但是,即使編譯無法知道有關create()中的T的任何信息,但是它仍舊可以在編譯期間確保你放置到result中的對象具有T類型,使其適合ArrayList<T>。*/
class ArrayMaker<T>{//運行時實際保存的是Class<Object>private Class<T> kind;public ArrayMaker(Class<T> kind) {//這個地方在運行時,把一個Class<T>賦給了Class<Object>this.kind=kind;}@SuppressWarnings("unckecked")T[] create(int size) {return (T[]) Array.newInstance(kind,size);}public static void test() {ArrayMaker<String> s = new ArrayMaker<>(String.class);String[] stringArray = s.create(9);
// System.out.println(Arrays.toString(stringArray));
}
}
class ListMaker<T>{List<T> create(){return new ArrayList<T>();}public static void test() {ListMaker<String> s = new ListMaker<>();List<String> strs = s.create();}
}
class FilledListMaker<T> {List<T> create(T t, int n) {List<T> result = new ArrayList<T>();for (int i = 0; i < n; i++) {result.add(t);}return result;}public static void test() {FilledListMaker<String> stringMaker = new FilledListMaker<>();List<String> list = stringMaker.create("Hello",4);System.out.println(list);}
}/*因為擦除在方法體中移除了類型信息,所以在運行時的問題就是邊界:即對象進入和離開方法的地點。這些正是編譯器在編譯期執行類型檢查并插入轉型代碼的地點。*/
?
轉載于:https://www.cnblogs.com/junjie2019/p/10551961.html
總結
以上是生活随笔為你收集整理的Java编程思想:擦除的神秘之处的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Nginx集群session管理的两种方
- 下一篇: (原创)7-1 银行业务队列简单模拟 (