《Data Structure and Algorithm Analysis in Java》中Java语言的重要特点 - 利用 Java 5 泛型特性实现泛型构件

1、简单的泛型类和接口

如下所示 MemoryCell 的泛型版本:

public class DSAA0103_GenericMemoryCell<AnyType>
{
    private AnyType storedValue;

    public AnyType read()
    {
        return storedValue;
    }

    public void write(AnyType x)
    {
        storedValue = x;
    }
}

当指定一个泛型类时,类的声明则包含一个或多个类型参数,这些参数被放在类名后面的一对尖括号内。

也可以声明接口是泛型的。

2、自动装箱/拆箱

Java 5 中,如果一个 int 型量被传递到需要一个 Integer 对象的地方,编译器将在幕后插入一个对 Integer 构造方法的调用,这就叫做自动装箱。而如果一个 Integer 对象被放到需要 int 型量的地方,编译器将在幕后插入一个对 intValue 方法的调用,这就叫做自动拆箱。

public class DSAA0103_GenericMemoryCellDemo
{
    public static void main(String[] args)
    {
        DSAA0103_GenericMemoryCell<Integer> m = new DSAA0103_GenericMemoryCell<Integer>();       

        m.write(5);
        int val = m.read();
        System.out.println("Contents are: " + val);
    }
}

3、菱形运算符

Java 7 增加了一种新的语言特性,称为菱形运算符,使得上述 DSAA0103_GenericMemoryCell<Integer> m = new DSAA0103_GenericMemoryCell<Integer>() 可以改写为:

DSAA0103_GenericMemoryCell<Integer> m = new DSAA0103_GenericMemoryCell<>();

因为既然 m 是 DSAA0103_GenericMemoryCell<Integer> 类型的,创建的对象也必须是 DSAA0103_GenericMemoryCell<Integer> 类型的,任何其他类型的参数都会产生编译错误。

泛型方法,特别像是泛型类,因为类型参数表使用相同的语法,在泛型方法中的类型参数位于返回类型之前。

4、带有限制的通配符

数组是协变的,泛型(以及泛型集合)不是协变的,Java 5 用通配符来表示参数类型的子类(或超类)。

5、类型限界

若要编写一个 findMax 例程,编译器只有在能证明 compareTo 的调用是合法的情况下,程序才能正常运行;只有在 AnyType 是 Comparable 的情况下才能保证 comareTo 存在。我们可以使用类型限界(type bound)解决这个问题。类型限界在尖括号内指定,它指定参数类型必须具有的性质。

比较好的方法是:

public static <AnyTpye extends Comparable<AnyType>> ...

然而,假设 Shape 实现 Comparable<Shape>,设 Square 继承 Shape。此时,只是 Square 实现 Comparable<Shape>。于是 Square IS-A Comparable<Shape>,但它 IS-NOT-A Comparable<Square>!

比如,AnyType IS-A Comparable<T>,其中,T 是 AnyType 的父类。因此可以使用通配符:

public static <AnyType extends Comparable<? super AnyType>>

findMax最终的实现如下,编译器接受类型 T 的数组,只是使得 T 实现 Comparable<S> 接口,其中 T IS-A S。

public class DSAA0104_GenericCompare
{
    public static <AnyType extends Comparable<? super AnyType>> AnyType findMax(AnyType[] arr)
    {
        int maxIndex = 0;

        for(int i= 1; i < arr.length; i++)
        {
            if(arr[i].compareTo(arr[maxIndex]) > 0)
                maxIndex = i;
        }

        return arr[maxIndex];
    }
}

6、函数对象

上述的泛型方法 findMax 有一个重要的局限:它只对实现 Comparable 接口对象有效,它使用 compareTo 作为所有比较决策的基础。有时,这不是我们想要的。

解决上述需求的方案是重写 findMax,使它接受两个参数:一个是对象的数组,另一个是比较函数。

一种将函数作为参数传递的方法就是,对象既包含数据也包含方法,可以定义一个没有数据而只有一个方法的类,并传递该类的一个实例。一个函数通过将其放在一个对象内部而传递,这样的对象通常叫做函数对象(function object)。

import java.util.*;

public class DSAA0104_GenericCompare
{
    public static <AnyType> AnyType findMax(AnyType[] arr, Comparator<? super AnyType> cmp)
    {
        int maxIndex = 0;

        for(int i= 1; i < arr.length; i++)
        {
            if(cmp.compare(arr[i], arr[maxIndex]) > 0)
                maxIndex = i;
        }

        return arr[maxIndex];
    }


    public static void main(String[] args)
    {
        //String[] arr = { "ZERRA", "alligator", "crocodile"};
        //System.out.println(findMax(arr, new CaseInsensitiveCompare()));

        Integer[] arr = {12, 23, 15};        
        System.out.println(findMax(arr, new revInteger()));
    }
}

class CaseInsensitiveCompare implements Comparator<String>
{
    public int compare(String lhs, String rhs)
    {
        return lhs.compareToIgnoreCase(rhs);
    }
}

class revInteger implements Comparator<Integer>
{
    public int compare(Integer li, Integer ri)
    {
        //return li.compareTo(ri);        
        return ri.compareTo(li);
    }
}

猜你喜欢

转载自www.cnblogs.com/Tom-1103/p/12040249.html