java编程思想读书笔记 第十五章 泛型(上)

1. 泛型简介 & 与 C++比较
泛型实现了参数化类型的概念,使代码可以应用于多种类型。“泛型”这个术语的意思是:“适用于许多许多的类型”。泛型最初的目的是希望类或方法能够具备最广泛的表达能力。如何做到这点呢?正是通过解耦类或方法与所使用的类型之间的约束。
因为 Java 的设计者曾经说过:设计 Java 的灵感主要来自 C++。所以我们就拿 Java 和 C++做一下对比吧:
首先,了解 C++模板的某些方面,有助于理解泛型的基础。 最终的目的是帮助我们理解 Java 泛型的边界在哪里。理解了边界所在才能成为程序高手,因为只有知道了某个技术不能做什么,才能更好的做到所能做的
第二点,在 Java 社区中,人们普遍对 C++模板有一种误解,令你有可能会在理解泛型的意图时产生偏差。

2. 简单泛型**
有许多原因促成了泛型的出现,而最引人注目的一个原因,就是为了创造容器类。容器,就是存放使用对象的地方,数组也是如此。事实上,所有的程序,在运行时都要求你持有一大堆对象,所以,容器类算得上最具重用性的类库之一。下面来看一个只能持有单个对象的类。当然,这个类可以明确指定其特有的对象的类型:

public class Automobile {}
class Holder{
        private Automobile automobile;
        public Holder(Automobile automobile){
            this.automobile = automobile;
        }
        Automobile get(){
            return automobile;
        }
    }

不过这个类无法持有其他类型的任何对象。我们不希望为碰到的每个类型都编写一个新的类。所以让这个类直接持有Object类型的对象:

public class Holder2 {
    private Object a;
    public Holder2 (Object object){
        this.a = object;
    }
    public void set(Object a){
        this.a = a;
    }
    public Object get() {
        return a;
    }
    public static void main(String[] args) {
        Holder2 holder2 = new Holder2(new Automobile());
        Automobile automobile = (Automobile) holder2.get();
        holder2.set("Not an Automobile");
        String string = (String) holder2.get();
        holder2.set(1);
        Integer x = (Integer) holder2.get();
    }
}

现在,Holder2可以存储任何类型的对象,在这个例子中,只用了一个Holder2对象,却先后存储了三种不同的类型的对象。
有些情况下,我们确实希望容器能够同时持有多种类型的对象。但是,我们只使用容器来存储一种类型的对象。泛型的主要目的之一就是用来指定容器要持有什么类型的对象,而且由编译器来保证类型的正确性。下面举个例子来使用泛型:

public class Holder3<T> {
    private T a;
    public Holder3(T a) {
        this.a = a;
    }
    private void set(T a) {
        this.a = a;
    }
    private T get() {
        return a;
    }
    public static void main(String[] args) {
        Holder3<Automobile> holder3 = new Holder3<Automobile>(new Automobile());
        Automobile automobile = holder3.get();
    }

这个例子显示是使用T作为类型参数,所以现在如果你要创建Holder3对象时,你就必须要指明想要持有什么类型的对象,将其置于尖括号内。并且,在你从Holder3中取出它持有的对象时,自动地就是正确的类型了。一般而言,你可以认为泛型与其他的类型差不多,只不过它们碰巧有类型参数罢了。然而,在使用泛型时,我们只需要指定它们的名称以及类型参数列表即可。

3.泛型接口
泛型也可以应用于接口。例如生成器,这是一种专门负责创建对象的类。不过,当使用生成器创建新的对象时,它不需要任何参数。也就是说,生成器无需额外的信息就知道如何创建新的对象。
一般而言,一个生成器只定义一个方法,该方法用以产生新的对象。在这里,就是next()方法。如:
public interface Generator{T next();}
方法next()的返回类型是参数化的T。下面使用一个例子来实现Generator接口:

public class Coffee {
    private static long counter = 0;
    private final long id = counter++;
    public String toString() {
        return getClass().getSimpleName() + " " +id;
    }
}
public class Mocha extends Coffee{}
public class Americano extends Coffee{}
public class CoffeeGenerator implements Generator<Coffee>,Iterable<Coffee>{
    private Class[] types = {Mocha.class,Americano.class};
    private static Random random = new Random(47);
    public CoffeeGenerator() {
    }
    private int size = 0;
    public CoffeeGenerator(int sz) {
        this.size = sz;
    }
    @Override
    public Iterator<Coffee> iterator() {        
        return new CoffeeIterator();
    }
    @Override
    public Coffee next() {
        try {
            return (Coffee)types[(random.nextInt(types.length))].newInstance();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
    class CoffeeIterator implements Iterator<Coffee>{
        int count = size;
        public  boolean hasNext() {
            return count > 0;
        }
        public Coffee next() {
            count -- ;
            return CoffeeGenerator.this.next();
        }
        public void remove(){
            throw new UnsupportedOperationException();
        }
    }
    public static void main(String[] args) {
        CoffeeGenerator generator = new CoffeeGenerator();
        for (int i = 0; i < 5; i++) {
            System.out.println(generator.next());
        }
        for (Coffee coffee : new CoffeeGenerator(5)) {
            System.out.println(coffee);
        }
    }
}
ouput:
Americano 0
Mocha 1
Americano 2
Mocha 3
Mocha 4
Americano 5
Mocha 6
Mocha 7
Americano 8
Americano 9

参数化的Generator接口确保next()的返回值是参数的类型。CoffeeGenerator同时还实现了Iterable接口,所以它可以在循环语句中使用。不过,它还需要一个“末端哨兵”来判断合适停止,这正是第二个构造器的功能。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值