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);
请注意,我们是如何能用String
和Integer
还有他们对应的collection
的。
编译器在你使用这些方法时(runtime)深深地知道,T element
和Collection<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){
}
}