java泛型详解

泛型是Java中一个非常重要的知识点,在Java集合类框架中泛型被广泛应用。本文我们将从零开始来看一下Java泛型的设计,将会涉及到通配符处理,以及让人苦恼的类型擦除。

1 泛型类

public class Box {
    private String object;
    public void set(String object) { this.object = object; }
    public String get() { return object; }
}

这种定义只能给object设置string类型的,我们开看泛型

public class Box {
    // T stands for "Type"
    private T t;
    public void set(T t) { this.t = t; }
    public T get() { return t; }
}

Box integerBox = new Box();
Box doubleBox = new Box();
Box stringBox = new Box();

2 泛型方法

public class Main {

    public static  void out(T t) {
        System.out.println(t.getClass().getName());
    }

    public static void main(String[] args) {
        out("findingsea");
        out(123);
        out(11.11);
        out(true);
    }
}

给出不同的变量类型,并输出他们的类民,下面是一个泛型类和泛型方法的结合

public class Util {
    public static  boolean compare(Pair p1, Pair p2) {
        return p1.getKey().equals(p2.getKey()) &&
               p1.getValue().equals(p2.getValue());
    }
}
public class Pair {
    private K key;
    private V value;
    public Pair(K key, V value) {
        this.key = key;
        this.value = value;
    }
    public void setKey(K key) { this.key = key; }
    public void setValue(V value) { this.value = value; }
    public K getKey()   { return key; }
    public V getValue() { return value; }
}

Pair p1 = new Pair<>(1, "apple");
Pair p2 = new Pair<>(2, "pear");
boolean same = Util.compare(p1, p2);

现在我们要实现这样一个功能,查找一个泛型数组中大于某个特定元素的个数,我们可以这样实现:

public static  int countGreaterThan(T[] anArray, T elem) {
    int count = 0;
    for (T e : anArray)
        if (e > elem)  // compiler error
            ++count;
    return count;
}

----边界符

但是这样很明显是错误的,因为除了short, int, double, long, float, byte, char等原始类型,其他的类并不一定能使用操作符>,所以编译器报错,那怎么解决这个问题呢?答案是使用边界符。

public interface Comparable {
    public int compareTo(T o);
}

public static > int countGreaterThan(T[] anArray, T elem) {
    int count = 0;
    for (T e : anArray)
        if (e.compareTo(elem) > 0)
            ++count;
    return count;
}
----通配符

首先我们先定义几个简单的类,下面我们将用到它:

class Fruit {}
class Apple extends Fruit {}
class Orange extends Fruit {}

public class GenericReading {
    static List apples = Arrays.asList(new Apple());
    static List fruit = Arrays.asList(new Fruit());
   static class CovariantReader {
    //返回的并不是list,注意是获取具体某一个元素
    T readCovariant(List list) {
        return list.get(0);
    }
}
static void f2() {
    CovariantReader fruitReader = new CovariantReader();
    Fruit f = fruitReader.readCovariant(fruit);
    Fruit a = fruitReader.readCovariant(apples);
}
public static void main(String[] args) {
    f2();
}
}

有没有觉得很爽酸。。。
有以下几点问题需要注意:
(1):

在Java中不允许创建泛型数组,类似下面这样的做法编译器会报错:
List[] arrayOfLists = new List[2];  // compile-time error

以下代码可以得出

public class ErasedTypeEquivalence {
    public static void main(String[] args) {
        Class c1 = new ArrayList().getClass();
        Class c2 = new ArrayList().getClass();
        System.out.println(c1 == c2); // true
    }
}

(2):
Java泛型很大程度上只能提供静态类型检查,然后类型的信息就会被擦除,所以像下面这样利用类型参数创建实例的做法编译器不会通过:

public static  void append(List list) {
    E elem = new E();  // compile-time error
    list.add(elem);
}

//利用反射解决
public static  void append(List list, Class cls) throws Exception {
    E elem = cls.newInstance();   // OK
    list.add(elem);
}

List ls = new ArrayList<>();
append(ls, String.class);

(3):
我们无法对泛型代码直接使用instanceof关键字,因为Java编译器在生成代码的时候会擦除所有相关泛型的类型信息

public static  void rtti(List list) {
    if (list instanceof ArrayList) {  // compile-time error
        // ...
 
//解决方法  
public static void rtti(List list) {
    if (list instanceof ArrayList) {  // OK; instanceof requires a reifiable type
        // ...
    }
}

工厂模式

接下来我们利用泛型来简单的实现一下工厂模式,首先我们先声明一个接口Factory:

public interface qqq:{
}

下面创建几个类
class Filter extends Part {}
class FuelFilter extends Filter {
    public static class Factory implements typeinfo.factory.Factory {
        public FuelFilter create() {
            return new FuelFilter();
        }
    }
}
class AirFilter extends Filter {
    public static class Factory implements typeinfo.factory.Factory {
        public AirFilter create() {
            return new AirFilter();
        }
    }
}

class Belt extends Part {}
class FanBelt extends Belt {
    public static class Factory implements typeinfo.factory.Factory {
        public FanBelt create() {
            return new FanBelt();
        }
    }
}
class GeneratorBelt extends Belt {
    public static class Factory implements typeinfo.factory.Factory {
        public GeneratorBelt create() {
            return new GeneratorBelt();
        }
    }
}

有关内部类自己可以google查阅

class Part {
    static List> partFactories =
        new ArrayList>();
    static {
       // 注意内部类的调用方法
        partFactories.add(new FuelFilter.Factory());
        partFactories.add(new AirFilter.Factory());
        partFactories.add(new FanBelt.Factory());
        partFactories.add(new PowerSteeringBelt.Factory());
    }
    private static Random rand = new Random(47);
    public static Part createRandom() {
        int n = rand.nextInt(partFactories.size());
        return partFactories.get(n).create();
    }
    public String toString() {
        return getClass().getSimpleName();
    }
}

看完工厂的代码觉得很精妙,现在觉得java代码还是很好玩的,下回有机会ji xu

你可能感兴趣的:(java泛型详解)