回答问题和练习:泛型

  • 编写一个泛型方法来计算集合中具有特定属性(例如,奇数整数,质数,回文数)的元素数。

    Answer :

public final class Algorithm {
    public static <T> int countIf(Collection<T> c, UnaryPredicate<T> p) {

        int count = 0;
        for (T elem : c)
            if (p.test(elem))
                ++count;
        return count;
    }
}

通用UnaryPredicateinterface的定义如下:

public interface UnaryPredicate<T> {
    public boolean test(T obj);
}

例如,以下程序对整数列表中的奇数整数进行计数:

import java.util.*;

class OddPredicate implements UnaryPredicate<Integer> {
    public boolean test(Integer i) { return i % 2 != 0; }
}

public class Test {
    public static void main(String[] args) {
        Collection<Integer> ci = Arrays.asList(1, 2, 3, 4);
        int count = Algorithm.countIf(ci, new OddPredicate());
        System.out.println("Number of odd integers = " + count);
    }
}

程序打印:

Number of odd integers = 2
  • 以下类会编译吗?如果没有,为什么?
public final class Algorithm {
    public static <T> T max(T x, T y) {
        return x > y ? x : y;
    }
}

答案 :否。大于(\>)运算符仅适用于原始数字类型。

  • 编写一种泛型方法来交换数组中两个不同元素的位置。

Answer :

public final class Algorithm {
    public static <T> void swap(T[] a, int i, int j) {
        T temp = a[i];
        a[i] = a[j];
        a[j] = temp;
    }
}
  • 如果编译器在编译时擦除所有类型参数,那么为什么要使用泛型?

答案 :您应使用泛型,因为:

  • Java 编译器在编译时对通用代码执行更严格的类型检查。

  • 泛型支持将编程类型作为参数。

  • 泛型使您可以实现泛型算法。

  • 类型擦除后,以下类转换为什么?

public class Pair<K, V> {

    public Pair(K key, V value) {
        this.key = key;
        this.value = value;
    }

    public K getKey(); { return key; }
    public V getValue(); { return value; }

    public void setKey(K key)     { this.key = key; }
    public void setValue(V value) { this.value = value; }

    private K key;
    private V value;
}

Answer :

public class Pair {

    public Pair(Object key, Object value) {
        this.key = key;
        this.value = value;
    }

    public Object getKey()   { return key; }
    public Object getValue() { return value; }

    public void setKey(Object key)     { this.key = key; }
    public void setValue(Object value) { this.value = value; }

    private Object key;
    private Object value;
}
  • 类型擦除后,以下方法转换为什么?
public static <T extends Comparable<T>>
    int findFirstGreaterThan(T[] at, T elem) {
    // ...
}

Answer :

public static int findFirstGreaterThan(Comparable[] at, Comparable elem) {
    // ...
    }
  • 可以编译以下方法吗?如果没有,为什么?
public static void print(List<? extends Number> list) {
    for (Number n : list)
        System.out.print(n + " ");
    System.out.println();
}

答案 :是的。

  • 编写泛型方法以在列表的\[begin, end\)范围内找到最大元素。

Answer :

import java.util.*;

public final class Algorithm {
    public static <T extends Object & Comparable<? super T>>
        T max(List<? extends T> list, int begin, int end) {

        T maxElem = list.get(begin);

        for (++begin; begin < end; ++begin)
            if (maxElem.compareTo(list.get(begin)) < 0)
                maxElem = list.get(begin);
        return maxElem;
    }
}
  • 以下类会编译吗?如果没有,为什么?
public class Singleton<T> {

    public static T getInstance() {
        if (instance == null)
            instance = new Singleton<T>();

        return instance;
    }

    private static T instance = null;
}

答案 :不能。您不能创建类型参数T的静态字段。

  • 给定以下类别:
class Shape { /* ... */ }
class Circle extends Shape { /* ... */ }
class Rectangle extends Shape { /* ... */ }

class Node<T> { /* ... */ }

以下代码可以编译吗?如果没有,为什么?

Node<Circle> nc = new Node<>();
Node<Shape>  ns = nc;

答案 :否。因为Node\<Circle\>不是Node\<Shape\>的子类型。

  • 考虑此类:
class Node<T> implements Comparable<T> {
    public int compareTo(T obj) { /* ... */ }
    // ...
}

以下代码可以编译吗?如果没有,为什么?

答案 :是的。

Node<String> node = new Node<>();
Comparable<String> comp = node;
  • 您如何调用以下方法在列表中查找相对于指定整数列表而言是素数的第一个整数?
public static <T>
    int findFirst(List<T> list, int begin, int end, UnaryPredicate<T> p)

请注意,如果 gcd(* a,b )= 1,则两个整数 a b *是相对质数,其中 gcd 是最大公约数的缩写。

Answer :

import java.util.*;

public final class Algorithm {

    public static <T>
        int findFirst(List<T> list, int begin, int end, UnaryPredicate<T> p) {

        for (; begin < end; ++begin)
            if (p.test(list.get(begin)))
                return begin;
        return -1;
    }

    // x > 0 and y > 0
    public static int gcd(int x, int y) {
        for (int r; (r = x % y) != 0; x = y, y = r) { }
            return y;
    }
}

通用的UnaryPredicateinterface定义如下:

public interface UnaryPredicate<T> {
    public boolean test(T obj);
}

以下程序测试findFirst方法:

import java.util.*;

class RelativelyPrimePredicate implements UnaryPredicate<Integer> {
    public RelativelyPrimePredicate(Collection<Integer> c) {
        this.c = c;
    }

    public boolean test(Integer x) {
        for (Integer i : c)
            if (Algorithm.gcd(x, i) != 1)
                return false;

        return c.size() > 0;
    }

    private Collection<Integer> c;
}

public class Test {
    public static void main(String[] args) throws Exception {

        List<Integer> li = Arrays.asList(3, 4, 6, 8, 11, 15, 28, 32);
        Collection<Integer> c = Arrays.asList(7, 18, 19, 25);
        UnaryPredicate<Integer> p = new RelativelyPrimePredicate(c);

        int i = ALgorithm.findFirst(li, 0, li.size(), p);

        if (i != -1) {
            System.out.print(li.get(i) + " is relatively prime to ");
            for (Integer k : c)
                System.out.print(k + " ");
            System.out.println();
        }
    }
}

程序打印:

11 is relatively prime to 7 18 19 25