java 泛型指导手册(中)

1.java中的类的泛型化

[原文](http://tutorials.jenkov.com/java-generics/classes.html

去泛型化你的java类也是可能的。泛型不限于javaAPI预先提供的那些类们。这里是一个示例:

public class GenericFactory<T> {

    Class theClass = null;

    public GenericFactory(Class theClass) {
        this.theClass = theClass;
    }

    public T createInstance()
    throws IllegalAccessException, InstantiationException {
        return (T) this.theClass.newInstance();
    }
}

那个<T>表示这个类初始化的时候,是有一个类型(type)的。这里是个例子:

GenericFactory<MyClass> factory =
    new GenericFactory<MyClass>(MyClass.class);

MyClass myClassInstance = factory.createInstance();

请注意,在使用factory.createInstance()的时候, 没有必要去转型,编译器会自动演算出GenerateFactory的泛型类型所指代的object的type

每一个GenericFactory的实例都能被泛型化为不同的类型。这里有两个例子:

GenericFactory<MyClass> factory =
    new GenericFactory<MyClass>(MyClass.class);

MyClass myClassInstance = factory.createInstance();


GenericFactory<SomeObject> factory =
    new GenericFactory<SomeObject>(SomeObject.class);

SomeObject someObjectInstance = factory.createInstance();

2. java中方法的泛型化

在java中,去泛型化一个方法也是可以的。如下:

public static <T> T addAndReturn(T element, Collection<T> collection){
    collection.add(element);
    return element;
}

这个方法同时指定了element和已经有泛型类型的Collection的类型(type)。
所以在上述的情况下,你可以在collecion里添加element
然而,你用一个通配符来指定collection的泛型类型,再添加element进去,这就不行了。

那么,编译器如何知道T的类型呢?

答案就是:编译器在你使用这个方法时推断了出来。给你一个例子:

String stringElement = "stringElement";
List<String> stringList = new ArrayList<String>();

String theElement = addAndReturn(stringElement, stringList);    


Integer integerElement = new Integer(123);
List<Integer> integerList = new ArrayList<Integer>();

Integer theElement = addAndReturn(integerElement, integerList); 

请注意,我们是如何能用StringInteger还有他们对应的collection的。
编译器在你使用这些方法时(runtime)深深地知道,T elementCollection<T> collection的参数定义。

编译器能完成更加牛逼的类型猜测。如下的调用是合法的:

String stringElement = "stringElement";
List<Object> objectList = new ArrayList<Object>();

Object theElement = addAndReturn(stringElement, objectList);   

这个例子中我们使用了两种不同的类型给addAndReturn()中的T:String和Object。
编译器会自动使用最合适的类型参数,以此让这个方法调用尽量正确。这里,它会猜测,T是Object(译者注:将String向上转型为Object是极为安全的)

下面给出一个很不合法的例子:

Object objectElement = new Object();
List<String> stringList = new ArrayList<String>();

Object theElement = addAndReturn(objectElement, stringList);

这种情况下,为了方法调用是安全的,编译器会猜测T应该是个String类型。传到第一个位置的参数(T element)这里对应的objectElement应该为一个String,但是objectElement真的不是String啊,所以呢,编译器这个时候就会报错。

3. java泛型-类对象作为类型字面值

类对象也可以作为类型指定符,在runtime。举例,你可以个创建一个泛型化的方法如下:

public static <T> T getInstance(Class<T> theClass)
    throws IllegalAccessException, InstantiationException {

    return theClass.newInstance();
}

这里是一些使用getInstance()的例子:

String string   = getInstance(String.class);

MyClass myClass = getInstance(MyClass.class);

正如你所见,返回值类型随着你传什么类型的类对象进去。在应付数据库的很多API的时候这种手段很好用。如下:

public static <T> T read(Class<T> theClass, String sql)
    throws IllegalAccessException, InstantiationException {

    //execute SQL.

    T o = theClass.newInstance();
    //set properties via reflection.

    return o;
}

你能像下面一样,来调用call()方法:

Driver employee   = read(Driver.class, "select * from drivers where id=1");

Vehicle vehicle   = read(Vehicle.class, "select * from vehicles where id=1");

java很聪明,不是吗?

4.java泛型-完善Iterable接口

(译者注:我跳过了for-each循环的翻译)

你也可以对你自己的类使用for-each循环。为了能这样做,你要把自己的类完善java.lang.Iterable<E>接口。

这里是基础示例:

public class MyCollection<E> implements Iterable<E>{

    public Iterator<E> iterator() {
        return new MyIterator<E>();
    }
}

对应的MyIterator的骨架如下:

public class MyIterator <T> implements Iterator<T> {

    public boolean hasNext() {

        //implement...
    }

    public T next() {
        //implement...;
    }

    public void remove() {
        //implement... if supported.
    }
}

然后你就能用for-each循环了:

public static void main(String[] args) {
    MyCollection<String> stringCollection = new MyCollection<String>();

    for(String string : stringCollection){

    }
}

猜你喜欢

转载自blog.csdn.net/paulkg12/article/details/76134021