Java编程思想-第15章 泛型(要点)

  一般的类和方法,只能使用具体的类型:要么是基本类型,要么是自定义的类。如果要编 写可以应用于多种类型的代码,这种刻板的限制对代码的束缚就会很大。

   在面向对象编程语言中,多态算是一种泛化机制。例如,你可以将方法的参数类型设为基 类,那么该方法就可以接受从这个基类中导出的任何类作为参数。这样的方法更加通用一些, 可应用的地方也多一些。在类的内部也是如此,凡是需要说明类型的地方,如果都使用基类, 确实能够具备更好的灵活性。但是,考虑到除了 final类不能扩展,其他任何类都可以被扩展 所以这种灵活性大多数时候也会有一些性能损耗。

  有时候,拘泥于单继承体系,也会使程序受限太多。如果方法的参数是一个接口,而不是 个类,这种限制就放松了许多。因为任何实现了该接口的类都能够满足该方法,这也包括暂 时还不存在的类。这就给予客户端程序员一种选择,他可以通过实现一个接口来满足类或方法 因此,接口允许我们快捷地实现类继承,也使我们有机会创建一个新类来做到这一点。

   可是有的时候,即便使用了接口,对程序的约束也还是太强了。因为一旦指明了接口,它 就要求你的代码必须使用特定的接口。而我们希望达到的目的是编写更通用的代码,要使代码 能够应用于“某种不具体的类型”,而不是一个具体的接口或类。

   这就是 Java SE5的重大变化之一:泛型的概念。泛型实现了参数化类型的概念,使代码可以 应用于多种类型。“泛型”这个术语的意思是:“适用于许多许多的类型”。泛型在编程语言中出 现时,其最初的目的是希望类或方法能够具备最广泛的表达能力。如何做到这一点呢,正是通 过解耦类或方法与所使用的类型之间的约束。稍后你将看到,Java中的泛型并没有这么高的追 求,实际上,你可能会质疑,Java中的术语“泛型”是否适合用来描述这一功能。

  如果你从未接触过参数化类型机制,那么,在学习了Java中的泛型之后,你会发现,对这 门语言而言,泛型确实是一个很有益的补充。在你创建参数化类型的一个实例时,编译器会为 你负责转型操作,并且保证类型的正确性。这应该是一个进步。

15.1 与C++比较

  Java中的泛型就需要与C++进行一番比较,理由有二:首先,了解C++模板的某些方面,有 助于你理解泛型的基础。同时,非常重要的一点是,你可以了解ava泛型的局限是什么,以及 为什么会有这些限制。最终的目的是帮助你理解,Java泛型的边界在哪里。根据我的经验,理 解了边界所在,你才能成为程序高手。因为只有知道了某个技术不能做到什么,你才能更好地 做到所能做的(部分原因是,不必浪费时间在死胡同里乱转)。 第二个原因是,在Java社区中,人们普遍对C++模板有一种误解,而这种误解可能会误导你, 令你在理解泛型的意图时产生偏差。

15.2 简单泛型

  有许多原因促成了泛型的出现,而最引人注目的一个原因,就是为了创造容器类。(关于容 器类,你可以参考第11章和第17章这两章。)容器,就是存放要使用的对象的地方。数组也是如 此,不过与简单的数组相比,容器类更加灵活,具备更多不同的功能。事实上,所有的程序, 在运行时都要求你持有一大堆对象,所以,容器类算得上最具重用性的类库之一。

15.2.1 一个元组类库

  仅一次方法调用就能返回多个对象,你应该经常需要这样的功能吧。可是 return语句只允许 返回单个对象,因此,解决办法就是创建一个对象,用它来持有想要返回的多个对象。当然 可以在每次需要的时候,专门创建一个类来完成这样的工作。可是有了泛型,我们就能够一次 性地解决该问题,以后再也不用在这个问题上浪费时间了。同时,我们在编译期就能确保类型 安全。 这个概念称为元组( tuple),它是将一组对象直接打包存储于其中的一个单一对象。这个容 器对象允许读取其中元素,但是不允许向其中存放新的对象。(这个概念也称为数据传送对象, 或信使。)

15.2.2 一个堆栈类 ---> write code

public class LinkedStack<T> {
	private static class Node<U>{
		U item;
		Node<U> next;
		Node(){item = null; next = null;}
		Node(U item,Node<U> next){
			this.item = item;
			this.next = next;
		}
		private 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;
	}
	// add new method popIsNull
	public boolean popIsNull(){
		if(top.end())
			return true;
		return false;
	}
	public static void main(String[] args) {
		LinkedStack<Integer> ls = new LinkedStack<Integer>();
		for(String str : "0 1 2 3 4 5 6 7 8 9 1999 9999".split(" "))
			ls.push(Integer.valueOf(str));
		//String s;
		while(!ls.popIsNull()){
			//if((s = ls.pop()) == null)
			//	break;
			System.out.print(ls.pop() + " ");
			
		}
		/*
		for(int i = 0; i < 15 ; i ++ )
			System.out.print(ls.pop() + " ");
		 * */
	}

}

 

15.2.3 RandomList ---> write code

import java.util.ArrayList;
import java.util.Random;

public class RandomList<T> {

    private ArrayList<T> storge = new ArrayList<T>();
    private Random rand = new Random();
    public void add(T t){
        storge.add(t);
    }
    public T select(){
        return storge.get(rand.nextInt(storge.size()));
    }
    public static void main(String[] args) {
        RandomList<String> rl = new RandomList<String>();
        for(String s : "0 1 2 3 4 5 6 7 8 9".split(" "))
            rl.add(s);
        for(int i = 0 ; i < rl.storge.size() ; i++)
            System.out.print(rl.select() + " ");

    }

}

 

15.3 泛型接口

  泛型也可以应用于接口。例如生成器( generator),这是一种专门负责创建对象的类。实际 上,这是工厂方法设计模式的一种应用。不过,当使用生成器创建新的对象时,它不需要任何 参数,而工厂方法一般需要参数。也就是说,生成器无需额外的信息就知道如何创建新对象。 般而言,一个生成器只定义一个方法,该方法用以产生新的对象。在这里,就是 nexto方 法。我将它收录在我的标准工具类库中:

public interface Generator<T>{
	T next();
}

 下面的类是Generator<T>接口的一个实现,它负责生成Fibonacci数列:

public class Fibonacci implements Generator<Integer>{
	private int count = 0;
	
	public Integer next() {
		
return fib(count ++); } private Integer fib(int n){ if(n < 2) return 1; return fib(n - 2) + fib(n - 1); } public static void main(String[] args) { Fibonacci f = new Fibonacci(); for (int i = 0; i < 10 ;i ++) System.out.print(f.next() + " "); //Test n = 9 System.out.print("[" + f.fib(9) + "]"); } }

 创建一个适配器来实现所需的接口

import java.util.Iterator;

public class IterableFibonacci extends Fibonacci 
			implements Iterable<Integer>{
	private int n;
	
	IterableFibonacci(int count){n = count;}
	
	public Iterator<Integer> iterator() {
		return new Iterator<Integer>(){

			public boolean hasNext() {
				n--;
				return  n >= 0;
			}

			public Integer next() {
				return IterableFibonacci.this.next();
			}
			
			public void remove(){
				throw new UnsupportedOperationException();
			}
			
		};
	}
	public static void main(String[] args) {
		IterableFibonacci iFib = new IterableFibonacci(18);
		for(int nf : iFib)
			System.out.print(nf + " ");
		/*
		IterableFibonacci iFib1 = new IterableFibonacci(18);
		Iterator<Integer> it = iFib1.iterator();
		System.out.println();
		for(int i = it.next() ;it.hasNext(); i = it.next() )
			System.out.print(i + " ");
		 * */
	}

}

 

15.4 泛型方法
  到目前为止,我们看到的泛型,都是应用于整个类上。但同样可以在类中包含参数化方法,而这个方法所在的类可以是泛型类,也可以不是泛型类。也就是说,是否拥有泛型方法,与其所在的类是否是泛型没有关系。

15.4.1 杠杆利用类型参数推断

15.4.2 可变参数与泛型

15.4.3 用于Generator的泛型方法

15.4.4 一个通用的Generator

package com.generic;

public class BasicGenerator<T> implements Generator<T> {
	private Class<T> type;
	
	private BasicGenerator(Class<T> type){
		this.type = type;
	}

	public T next() {
		try {
			return type.newInstance();
		} catch (Exception e) {
			
			throw new RuntimeException();
		} 
	}

	public static <T>Generator<T> create(Class<T> type){
		return new BasicGenerator<T>(type);
	}
}

 

public class CountedObject {
	private static  long counter = 0;
	private final long id = counter ++;
	public long getId(){return id;}
	public String toString(){
		return "CountedObject " + id;
	}
}

 

public class BasicGeneratorDemo {

	public static void main(String[] args) {
		Generator<CountedObject> g = BasicGenerator.create(CountedObject.class);
		for(int i = 0 ;i < 6 ;i ++)
			System.out.println(g.next());
	}

}

 

15.4.5 简化元组的使用

15.4.6 一个Set实用工具

15.5 匿名内部类

public class Customer {
	private static  long counter = 1;
	private final long id = counter ++;
	private Customer(){}
	public long getId(){return id;}
	public String toString(){
		return "Customer " + id;
	}
	public static Generator<Customer> generator(){
		return new Generator<Customer>(){
			public Customer next() {
				return new Customer();
			}
			
		};
	}
}

 

public class Teller {
	private static  long counter = 1;
	private final long id = counter ++;
	private Teller(){}
	public long getId(){return id;}
	public String toString(){
		return "Teller " + id;
	}
	public static Generator<Teller> generator(){
		return new Generator<Teller>(){
			public Teller next() {
				return new Teller();
			}
			
		};
	}
}

 

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import java.util.Random;

public class BankTeller {
	public static String serve(Teller t,Customer c){
		return t + " Serve " + c;
	}
	public static void main(String[] args) {
		Random rand = new Random(47);
		Queue<Customer> line = new LinkedList<Customer>();
		Generators.fill(line,Customer.generator(), 15);
		List<Teller> tllerList = new ArrayList<Teller>();
		Generators.fill(tllerList,Teller.generator(), 4);
		for(Customer c : line)
			System.out.println(serve(tllerList.get(rand.nextInt(tllerList.size())),c));
	}

}

 *// Output:

Teller 3 Serve Customer 1
Teller 2 Serve Customer 2
Teller 3 Serve Customer 3
Teller 1 Serve Customer 4
Teller 1 Serve Customer 5
Teller 3 Serve Customer 6
Teller 1 Serve Customer 7
Teller 2 Serve Customer 8
Teller 3 Serve Customer 9
Teller 3 Serve Customer 10
Teller 2 Serve Customer 11
Teller 4 Serve Customer 12
Teller 2 Serve Customer 13
Teller 1 Serve Customer 14
Teller 1 Serve Customer 15

*///

15.6 构建复杂模型

15.7 ~ 15.19  节更深入的讲解

posted @ 2018-03-28 14:51  JackYgy  阅读(257)  评论(0)    收藏  举报