Thinking In Java Part09(泛型類、泛型方法)

1、接口與類型信息
	interface關鍵字的一種重要目標就是允許程序員隔離構件,進而降低耦合性。
	javap -private C 可以反編譯顯示出這個類的所有方法,無論private還是匿名
2、泛型
	實現了參數化類型的概念,使代碼可以應用於多種類型。術語的意思爲:“適用於許多許多的類型”。最初的目的是希望類或方法能夠具備最廣泛的表達能力,通過解耦類或方法與所使用的類型之間的約束。
	泛型的主要目的之一就是用來指定容器要持有什麼類型的對象,而且由編譯器來保證類型的正確性。
	核心概念:告訴編譯器想使用什麼類型,然後編譯器幫你處理一切細節。
3、一個元組類庫
	元組:將一組對象直接打包存儲於其中的一個單一對象。這個容器對象允許讀取其中元素,但是不允許向其中存放新的對象(也被稱爲數據傳送對象或信使)。
	元組可以具有任意長度,對象可以是任意不同的類型,但是希望可以指明其類型。
	不用LinkedList實現內部鏈式存儲機制
	public class ContainerTest01 {
	    public static void main(String[] args) {
	        LinkedStack<String> lss = new LinkedStack<>();
	        for(String s : "hello world".split(" ")){
	            lss.push(s);
	        }
	        String s;
	        while((s = lss.pop()) !=null){
	            System.out.println(s);
	        }
	    }
	}

	class LinkedStack<T> {
	    @AllArgsConstructor
	    @Data
	    @NoArgsConstructor
	    private static class Node<U> {
	        U item;
	        Node<U> next;

	        boolean end() {
	            return item == null && next == null;
	        }
	    }
	    private Node<T> top = new Node<T>();
	    public void push(T item){
	        top = new Node<T>(item,top);
	    }
	    public T pop(){
	        T result = top.item;
	        if(! top.end()){
	            top = top.next;
	        }
	        return result;
	    }
	}
	使用了末端哨兵(end sentinel)來判斷堆棧何時爲空。在構造LinkedStack的時候創建的空Node就是末端哨兵。之後,每調用一次push方法,就會創建一個Node對象,並將其鏈接到前一個Node對象。當調用pop方法時,返回top.item並丟棄大當前top所指向的Node,並將top轉譯到下一個Node,除非碰到了末端哨兵,這時候不再移動top。當到了末端,繼續調用pop只會得到null,說明堆棧爲空。
4、泛型接口
	泛型應用於接口,生成器:專門負責創建對象的類。是工廠方法設計模式的一種應用,不過使用生成器創建新的對象時,不需要參數,無需額外的信息就知道如何創建新對象。
	一般,一個生成器只定義一個方法,用以產生新的對象。
	public interface Generator<T> {
	    T next();
	}
	生成的類
	public class Coffee {
	    static long counter = 0;
	    final long id = counter++;

	    @Override
	    public String toString() {
	        return getClass().getSimpleName() + " " + id;
	    }
	}
	class Latte extends Coffee {
	}

	class Mocha extends Coffee {
	}

	class Cappuccino extends Coffee {
	}

	class Breve extends Coffee {
	}
	實現Generator<Coffee>接口來隨機生成不同類型的Coffee對象
	@NoArgsConstructor
	class CoffeeGenerator implements Generator<Coffee>, Iterable<Coffee> {
	    private Class[] types = {Latte.class, Mocha.class, Cappuccino.class, Breve.class};
	    private static Random rand = new Random(47);
	    private int size = 0;

	    public CoffeeGenerator(int sz) {
	        size = sz;
	    }

	    @Override
	    public Coffee next() {
	        try {
	            return (Coffee) types[rand.nextInt(types.length)].newInstance();
	        } catch (Exception e) {
	            throw new RuntimeException(e);
	        }
	    }

	    class CoffeeIterator implements Iterator<Coffee> {
	        int count = size;

	        @Override
	        public boolean hasNext() {
	            return count > 0;
	        }

	        @Override
	        public Coffee next() {
	            count--;
	            return CoffeeGenerator.this.next();
	        }
	        @Override
	        public void remove(){
	            throw new UnsupportedOperationException();
	        }
	    }

	    @Override
	    public Iterator<Coffee> iterator() {
	        return new CoffeeIterator();
	    }
        public static void main(String[] args) {
	        CoffeeGenerator coffees = new CoffeeGenerator();
	        for (int i = 0; i < 4; i++) {
	            System.out.println(coffees.next());
	        }
	        for (Coffee c : new CoffeeGenerator(4)) {
	            System.out.println(c);
	        }
	    }
	}
	參數化的Generator接口確保next()返回值是參數的類型,同時還是先了Iterable接口,讓他可以在循環語句中用,還有個size來判斷何時停止。
	public class Fibonacci implements Generator<Integer> {
	    private int count = 0;

	    @Override
	    public Integer next() {
	        return fib(count++);
	    }

	    public int fib(int n) {
	        if (n < 2) {
	            return 1;
	        }
	        return fib(n - 2) + fib(n - 1);
	    }

	    public static void main(String[] args) {
	        Fibonacci fibonacci = new Fibonacci();
	        for (int i = 0; i < 18; i++) {
	            System.out.println(fibonacci.next() + "");
	        }
	    }
	}
	內部使用的int但是參數卻是Integer,Java泛型有一個侷限性:基本類型無法作爲類型參數。
	如果想要一個實現了Iterable的Fibonacci生成器,我們可以重寫這個類,但是不一定總有權限,因此,我們可以選擇創建一個適配器來實現所需接口。
	現在我們通過繼承來創建適配器類。
	class IterableFibonacci extends Fibonacci implements Iterable<Integer> {
	    private int n;

	    public IterableFibonacci(int count) {
	        n = count;
	    }

	    @Override
	    public Iterator<Integer> iterator() {
	        return new Iterator<Integer>() {
	            @Override
	            public boolean hasNext() {
	                return n > 0;
	            }

	            @Override
	            public Integer next() {
	                n--;
	                return IterableFibonacci.this.next();
	            }
	        };
	    }

	}
5、泛型方法
	泛型方法使得該方法能夠獨立於類而產生變化。基本的指導原則:無論何時,只要你能做到,你就應該儘量使用泛型方法。如果使用泛型方法可以取代將整個類泛型化,那麼就應該使用泛型方法,因爲可以使事情更清楚明白。
	當使用泛型類時,必須在創建對象時指定類型參數的值,而使用泛型方法時,通常不必指明參數類型,因爲編譯器會爲我們找出具體的類型。這稱爲類型參數推斷(type argument inference)。因此,我們可以調用普通方法一樣調用泛型方法,就好像泛型方法被無限次重載過。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章