- 浏览: 243996 次
- 性别:
- 来自: 北京
文章分类
最新评论
-
问道721:
长见识了, 新建文档还不行, 写入内容后就可以了
利用poi操作word文档 -
laodongbao:
终于找到了我能理解和接受的的spring aop和动态代理的结 ...
spring Aop中动态代理 -
lqservlet:
可以看到存储文件! 全是xml文件,好多呀。
利用poi操作word文档 -
步青龙:
直接重命名xx.docx的文件为xx.zip,用WinRar打 ...
利用poi操作word文档 -
邦者无敌:
如果是JDK1.3呢?是否要将上面四个jar包手动加入
com.sun.crypto.provider.SunJCE
泛型允许对类型进行抽象,最常见的泛型类是容器类。例如:
List<String> list = new ArrayList<String>();
list.add("1");
list.add("2");
for(String s: list) {
System.out.println(s);
} 以上例子中,如果试图向list中添加一个Integer对象,那么会导致编译错误。编译器会进行类型检查,这避免了使用非泛型容器类时常见的强制类型转换。泛型类是具有一个或者多个类型变量(type variable)的类。以下是个简单的例子:
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class Bag<E> {
private List<E> bag = new ArrayList<E>();
public Iterator<E> iterator() {
return this.bag.iterator();
}
public boolean add(E e) {
return this.bag.add(e);
}
public boolean remove(Object o) {
return this.bag.remove(o);
}
public boolean contains(Object e) {
return this.bag.contains(e);
}
public boolean addAll(Bag<? extends E> b) {
return this.bag.addAll(b.bag);
}
public boolean removeAll(Bag<?> b) {
return this.bag.removeAll(b.bag);
}
public boolean containsAll(Bag<?> b) {
return this.bag.containsAll(b.bag);
}
public void clear() {
this.bag.clear();
}
List<E> getBag() {
return this.bag;
}
}import java.util.Collections;
import java.util.Comparator;
public class Bags {
public static <E> void sort(Bag<E> b, Comparator<? super E> c) {
Collections.sort(b.getBag(), c);
}
public static <T extends Comparable<? super T>> T max(Bag<T> b) {
return Collections.max(b.getBag());
}
public static <E> void copy(Bag<E> dest, Bag<? extends E> src) {
dest.addAll(src);
}
} 需要注意的是,不能抛出或者捕获泛型类的实例,泛型类继承自Throwable也是不合法的。此外也不能声明泛型类实例的数组,例如以下代码会造成编译错误:
Bag<Integer> b3[] = new Bag<Integer>[10]; // Cannot create a generic array of Bag<Integer>
2 泛型方法
泛型方法是指带有类型参数的方法,类型变量的位置是修饰符和返回类型之间。在调用泛型方法的时候,具体类型的位置是方法名前的尖括号中,在绝大多数的情况下,由于编译器可以判断出具体类型,因此也可以省略具体类型。以下是个简单的例子:
public class Base {
public String getName() {
return "Base";
}
public static <T> void print(T t) {
System.out.println(t.toString());
}
public static void main(String args[]) {
Base base = new Base();
Base.<Base>print(base);
Base.print(base);
}
} 以上例子中的print方法内只能调用T从Object类继承的方法。如果希望将T限定为Base及其子类,那么可以使用extends设定上限,或者使用super设定下限(C++中不能限定参数变量的类型),例如:
public static <T extends Base> void print(T t) {
System.out.println(t.getName());
} 类型变量也可以有多个限定,限定类型用&分割。如果限定类型可以包含多个接口,但是至多有一个类(单继承),如果有一个类,那么它必须是第一个限定类型。例如:
T extends Comparable & Serializable
3 擦除
编译器会为每个泛型类型自动提供一个原始类型(raw type)。其类型变量会被擦除,并用其限定类型代替,如果没有限定类型,那么使用Object。不能使用原始数据类型作为类型变量,例如没有Bag<int>,但是可以有Bag<Integer>。
由于类型变量不存在于运行时,因此Java泛型没有C++模板类的代码膨胀问题。但是也有批评人士认为:如果你打算表示“任何类型”,那么Java会把这个任何类型转化为Object。这只能说Java的泛型只是对Object类型的一个泛化而已。Java泛型只是解决了容器类之间的自动转型罢了。
由于类型变量会被擦除,因此不管泛型类的类型变量是什么,它的所有实例的运行时类是相同的,例如以下代码的输出如下:
Bag<Integer> b1 = new Bag<Integer>();
Bag<String> b2 = new Bag<String>();
System.out.println(b1.getClass());
System.out.println(b2.getClass());
System.out.println(b1.getClass() == b2.getClass()); class Bag
class Bag
true
由于类的静态成员变量和成员方法也被类的所有实例共享,因此不能在类的静态成员变量和成员方法中引用类型变量。例如以下的代码会导致编译错误:
public class Bag<E> {
private static E INSTANCE; // Cannot make a static reference to the non-static type E
public static E getInstance() { // Cannot make a static reference to the non-static type E
return INSTANCE;
}
} 不能通过类型变量构造实例,但是可以通过Class.newInstance和Array.newInstance来构造实例。例如以下的代码会造成编译错误:
public Bag() {
E e1 = new E(); // Cannot instantiate the type E
E e2[] = new E[10];
} 在擦除后,也不能引起冲突。考虑如下代码:
public class Bag<E> {
public boolean equals(E e) { // Name clash: The method equals(E) of type Bag<E> has the same erasure as equals(Object) of type Object but does not override it
return true;
}
} 以上的Bag类的类型变量被擦除后的代码如下:
public class Bag<E> {
public boolean equals(Object e) {
return true;
}
} 其equals方法与Object.equals(Object obj)方法冲突。
4 泛型和继承
首先考虑如下代码:
public class Base {
private String id;
public String getName() {
return "Base";
}
public final String getId() {
return id;
}
public final void setId(String id) {
this.id = id;
}
}public class Derived extends Base {
public String getName() {
return "Derived";
}
public static void main(String args[]) {
//
Base base = new Base();
Derived derived = new Derived();
List<Base> list = new ArrayList<Base>();
list.add(base);
list.add(derived);
//
List<Derived> list2 = new ArrayList<Derived>();
List<Base> list3 = list2; // Type mismatch: cannot convert from List<Derived> to List<Base>
//
List list4 = list2;
list4.add(new Integer(1));
for(Object o : list4) {
System.out.println(o);
}
try {
for(Base b : list2) {
System.out.println(b); // Runtime Exception
}
} catch(ClassCastException e) {
e.printStackTrace();
}
//
List<?> list5 = list2;
}
} 泛型类可以继承或者实现其它泛型类或接口,例如ArrayList<T>实现了List<T>接口。因此ArrayList<Base>可以被转换成List<Base>,此外向List<Base>中添加base和derived也是合法的。
但是将list2赋值给list3会导致编译错误,就像关于继承的那个经典问题一样:苹果可以是水果的子类,但是能够装苹果的袋子不是能够装水果的袋子的子类。将list2赋值给list4和是合法的,但是如果向list4中添加一个Integer对象,那么在访问list2的时候会导致运行时异常。
list5使用了通配符,这在稍后会介绍。
5 通配符
在引入泛型之前,遍历Collection的方法通常如下:
public static void visit(Collection c) {
for(Iterator iter = c.iterator(); iter.hasNext(); ) {
System.out.println(iter.next());
}
}
public static void main(String args[]) {
List list = new ArrayList();
list.add("1");
visit(list);
} 使用泛型后,可以写成:
public static void visit(Collection<Object> c) {
for(Object o : c) {
System.out.println(o);
}
}
public static void main(String args[]) {
List<String> list = new ArrayList();
list.add("1");
visit(list); // The method visit(Collection<Object>) in the type Test is not applicable for the argument (List<String>)
} 由于List<String>并不是Collection<Object>的子类(Collection<Object>并不是所有类型的集合的父类型),因此调用visit(list)会造成编译错误。为了解决这个问题,Java泛型引入了通配符“?”。Collection<?>是所有类型的集合的父类型,叫做“未知集合”。
需要注意的是,向“未知集合”中添加对象不是类型安全的,这会导致编译错误,唯一例外的是null。此外从“未知集合”中获得的对象的类型也只能是Object类型。例如:
Collection<?> c = new ArrayList<String>();
c.add("1"); // The method add(capture#1-of ?) in the type Collectoin<capture#1 of ?> is not applicable for the arguments (String)
c.add(null);
Object o = c.get(0);
5.1 有界通配符
5.1.1 上界
可以使用extends为通配符限定上界,例如以下代码中限定了通配符的上界是Base类:
public static void visit(Collection<? extends Base> c) {
for(Base b : c) {
System.out.println(b);
}
}
public static void main(String args[]) {
List<Base> list = new ArrayList<Base>();
list.add(new Base());
list.add(new Derived());
visit(list);
} 在visit方法中,同样不能向c中添加非null对象。例如以下代码会造成编译错误:
public static void visit(Collection<? extends Base> c) {
c.add(new Derived()); // The method add(capture#1-of ? extends Base) in the type Collection<capture#1 -of ? extends Base> is not applicable for the arguments(Derived)
} 有时也可以不使用通配符而达到相同的目的,例如:
public static <T> void copy(List<T> dest, list< ? extends T> src) {
...
}
public static <T, S extends T> void copy(List<T> dest, List<S> src) {
...
}
5.1.2 下界
可以使用super为通配符限定下界,考虑以下代码:
public class Derived extends Base implements Comparable<Object> {
public int compareTo(Object obj) {
return System.identityHashCode(this) - System.identityHashCode(obj);
}
public static <T extends Comparable<T>> T max(Collection<T> c) {
return Collections.max(c);
}
public static void main(String args[]) {
List<Derived> list = new ArrayList<Derived>();
list.add(new Derived());
Derived.max(list); // Bound mismatch: The generic method max(Collection<T>) of type Derived is not applicable for the arguments (List<Derived>). The inferred type Derived is not a valid substitute for the bounded parameter <T extends Comparable<T>>
}
} 以上的max方法中限定了T类型必须实现了Comparable<T>接口,那么在main方法中以list为参数调用max方法会导致编译错误,这是因为Derived类没有实现Comparable<Derived>接口。这样的限制有些严格,如果将max方法改成如下方式,可以带来更大的灵活性。
public static <T extends Comparable<? super T>> T max(Collection<T> c) {
return Collections.max(c);
} 以下的代码虽然没有太大的意义,但是需要注意的是,在print方法中,p.setFirst()方法和p.setSecond()方法的参数类型为T,但是p.getFirst()方法和p.getSecond()方法的返回值类型只能是Object型。
public class Pair<T> {
//
private T first;
private T second;
public Pair(T first, T second) {
this.first = first;
this.second = second;
}
public T getFirst() {
return first;
}
public void setFirst(T first) {
this.first = first;
}
public T getSecond() {
return second;
}
public void setSecond(T second) {
this.second = second;
}
public void print(Pair<? super T> p) {
Object first = p.getFirst();
Object second = p.getSecond();
System.out.println("first: " + first + ", second: " + second);
}
public static void main(String args[]) {
Pair<Derived> p1 = new Pair<Derived>(new Derived(), new Derived());
Pair<Base> p2 = new Pair<Base>(new Base(), new Base());
p1.print(p2);
}
}
5.2 通配符捕获
考虑为Pair类编写一个方法,用于交换first和second。由于通配符不是变量类型,那么如下的写法是非法的:
? t = p.getFirst(); 此外,以下的写法也会导致编译错误:
public static void swap(Pair<?> p) {
Object first = p.getFirst();
p.setFirst(p.getSecond()); // //The method setFirst(captur#4-of ?) in the type Pair<capture#4-of ?> is not applicable for the arguments (capture#5-of ?)
p.setSecond(first); // The method setFirst(captur#6-of ?) in the type Pair<capture#6-of ?> is not applicable for the arguments (Object)
} 可以通过一个额外的泛型方法中的类型参数来捕获通配符,例如:
public static void swap(Pair<?> p) {
doSwap(p);
}
private static <T> void doSwap(Pair<T> p) {
T first = p.getFirst();
p.setFirst(p.getSecond());
p.setSecond(first);
}
6 泛型和反射
Class类是泛型的,而且实现了java.lang.reflect.Type接口。Class类没有公共构造方法。Class对象是在加载类时由 Java 虚拟机以及通过调用类加载器中的 defineClass 方法自动构造的。Class类的newInstance方法通过默认的构造函数返回类型为T的对象。例如:
public static <T> Pair<T> make(Class<T> c) throws InstantiationException, IllegalAccessException {
return new Pair<T>(c.newInstance(), c.newInstance());
}
Pair<String> ps = Pair.make(String.class); 接口 TypeVariable<D extends GenericDeclaration>,ParameterizedType, WildcardType,GenericArrayType继承自Type,用于通过反射获得泛型类型的信息(尽管进行了擦除)。
TypeVariable 表示各种类型变量。其getName()方法返回在源码中声明的变量名;getBounds()方法返回类型变量上边界Type对象数组;getGenericDeclaration()返回GenericDeclaration对象,以表示声明此类型变量的一般声明。
ParameterizedType 表示参数化类型,例如Collection<String>。其getRawType()返回原始类型,也就是声明此类型的类或接口;getActualTypeArguments()方法返回表示此类型实际类型参数的 Type对象数组。
WildcardType 表示一个通配符类型表达式,如 ?、? extends Number 或 ? super Integer。getLowerBounds()方法返回类型变量下边界Type对象数组;getUpperBounds()方法返回类型变量上边界Type对象数组。
GenericArrayType 表示一种数组类型,其组件类型为参数化类型或类型变量。getGenericComponentType() 返回此数组的元素类型的Type对象。
关于以上接口的详细文档,请参考Javadoc。以下是一个简单的例子,用于获得类型变量的Class类型:
import java.lang.reflect.ParameterizedType;
public abstract class GenericBase<T extends Comparable<? super T>> {
//
private Class<T> clazz;
@SuppressWarnings("unchecked")
public GenericBase() {
ParameterizedType pt = (ParameterizedType)getClass().getGenericSuperclass();
clazz = (Class<T>)pt.getActualTypeArguments()[0];
}
public Class<T> getClazz() {
return clazz;
}
public void setClazz(Class<T> clazz) {
this.clazz = clazz;
}
}
public class GenericDerived extends GenericBase<String> {
public static void main(String args[]) {
GenericDerived gd = new GenericDerived();
System.out.println(gd.getClazz());
}
}
List<String> list = new ArrayList<String>();
list.add("1");
list.add("2");
for(String s: list) {
System.out.println(s);
} 以上例子中,如果试图向list中添加一个Integer对象,那么会导致编译错误。编译器会进行类型检查,这避免了使用非泛型容器类时常见的强制类型转换。泛型类是具有一个或者多个类型变量(type variable)的类。以下是个简单的例子:
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class Bag<E> {
private List<E> bag = new ArrayList<E>();
public Iterator<E> iterator() {
return this.bag.iterator();
}
public boolean add(E e) {
return this.bag.add(e);
}
public boolean remove(Object o) {
return this.bag.remove(o);
}
public boolean contains(Object e) {
return this.bag.contains(e);
}
public boolean addAll(Bag<? extends E> b) {
return this.bag.addAll(b.bag);
}
public boolean removeAll(Bag<?> b) {
return this.bag.removeAll(b.bag);
}
public boolean containsAll(Bag<?> b) {
return this.bag.containsAll(b.bag);
}
public void clear() {
this.bag.clear();
}
List<E> getBag() {
return this.bag;
}
}import java.util.Collections;
import java.util.Comparator;
public class Bags {
public static <E> void sort(Bag<E> b, Comparator<? super E> c) {
Collections.sort(b.getBag(), c);
}
public static <T extends Comparable<? super T>> T max(Bag<T> b) {
return Collections.max(b.getBag());
}
public static <E> void copy(Bag<E> dest, Bag<? extends E> src) {
dest.addAll(src);
}
} 需要注意的是,不能抛出或者捕获泛型类的实例,泛型类继承自Throwable也是不合法的。此外也不能声明泛型类实例的数组,例如以下代码会造成编译错误:
Bag<Integer> b3[] = new Bag<Integer>[10]; // Cannot create a generic array of Bag<Integer>
2 泛型方法
泛型方法是指带有类型参数的方法,类型变量的位置是修饰符和返回类型之间。在调用泛型方法的时候,具体类型的位置是方法名前的尖括号中,在绝大多数的情况下,由于编译器可以判断出具体类型,因此也可以省略具体类型。以下是个简单的例子:
public class Base {
public String getName() {
return "Base";
}
public static <T> void print(T t) {
System.out.println(t.toString());
}
public static void main(String args[]) {
Base base = new Base();
Base.<Base>print(base);
Base.print(base);
}
} 以上例子中的print方法内只能调用T从Object类继承的方法。如果希望将T限定为Base及其子类,那么可以使用extends设定上限,或者使用super设定下限(C++中不能限定参数变量的类型),例如:
public static <T extends Base> void print(T t) {
System.out.println(t.getName());
} 类型变量也可以有多个限定,限定类型用&分割。如果限定类型可以包含多个接口,但是至多有一个类(单继承),如果有一个类,那么它必须是第一个限定类型。例如:
T extends Comparable & Serializable
3 擦除
编译器会为每个泛型类型自动提供一个原始类型(raw type)。其类型变量会被擦除,并用其限定类型代替,如果没有限定类型,那么使用Object。不能使用原始数据类型作为类型变量,例如没有Bag<int>,但是可以有Bag<Integer>。
由于类型变量不存在于运行时,因此Java泛型没有C++模板类的代码膨胀问题。但是也有批评人士认为:如果你打算表示“任何类型”,那么Java会把这个任何类型转化为Object。这只能说Java的泛型只是对Object类型的一个泛化而已。Java泛型只是解决了容器类之间的自动转型罢了。
由于类型变量会被擦除,因此不管泛型类的类型变量是什么,它的所有实例的运行时类是相同的,例如以下代码的输出如下:
Bag<Integer> b1 = new Bag<Integer>();
Bag<String> b2 = new Bag<String>();
System.out.println(b1.getClass());
System.out.println(b2.getClass());
System.out.println(b1.getClass() == b2.getClass()); class Bag
class Bag
true
由于类的静态成员变量和成员方法也被类的所有实例共享,因此不能在类的静态成员变量和成员方法中引用类型变量。例如以下的代码会导致编译错误:
public class Bag<E> {
private static E INSTANCE; // Cannot make a static reference to the non-static type E
public static E getInstance() { // Cannot make a static reference to the non-static type E
return INSTANCE;
}
} 不能通过类型变量构造实例,但是可以通过Class.newInstance和Array.newInstance来构造实例。例如以下的代码会造成编译错误:
public Bag() {
E e1 = new E(); // Cannot instantiate the type E
E e2[] = new E[10];
} 在擦除后,也不能引起冲突。考虑如下代码:
public class Bag<E> {
public boolean equals(E e) { // Name clash: The method equals(E) of type Bag<E> has the same erasure as equals(Object) of type Object but does not override it
return true;
}
} 以上的Bag类的类型变量被擦除后的代码如下:
public class Bag<E> {
public boolean equals(Object e) {
return true;
}
} 其equals方法与Object.equals(Object obj)方法冲突。
4 泛型和继承
首先考虑如下代码:
public class Base {
private String id;
public String getName() {
return "Base";
}
public final String getId() {
return id;
}
public final void setId(String id) {
this.id = id;
}
}public class Derived extends Base {
public String getName() {
return "Derived";
}
public static void main(String args[]) {
//
Base base = new Base();
Derived derived = new Derived();
List<Base> list = new ArrayList<Base>();
list.add(base);
list.add(derived);
//
List<Derived> list2 = new ArrayList<Derived>();
List<Base> list3 = list2; // Type mismatch: cannot convert from List<Derived> to List<Base>
//
List list4 = list2;
list4.add(new Integer(1));
for(Object o : list4) {
System.out.println(o);
}
try {
for(Base b : list2) {
System.out.println(b); // Runtime Exception
}
} catch(ClassCastException e) {
e.printStackTrace();
}
//
List<?> list5 = list2;
}
} 泛型类可以继承或者实现其它泛型类或接口,例如ArrayList<T>实现了List<T>接口。因此ArrayList<Base>可以被转换成List<Base>,此外向List<Base>中添加base和derived也是合法的。
但是将list2赋值给list3会导致编译错误,就像关于继承的那个经典问题一样:苹果可以是水果的子类,但是能够装苹果的袋子不是能够装水果的袋子的子类。将list2赋值给list4和是合法的,但是如果向list4中添加一个Integer对象,那么在访问list2的时候会导致运行时异常。
list5使用了通配符,这在稍后会介绍。
5 通配符
在引入泛型之前,遍历Collection的方法通常如下:
public static void visit(Collection c) {
for(Iterator iter = c.iterator(); iter.hasNext(); ) {
System.out.println(iter.next());
}
}
public static void main(String args[]) {
List list = new ArrayList();
list.add("1");
visit(list);
} 使用泛型后,可以写成:
public static void visit(Collection<Object> c) {
for(Object o : c) {
System.out.println(o);
}
}
public static void main(String args[]) {
List<String> list = new ArrayList();
list.add("1");
visit(list); // The method visit(Collection<Object>) in the type Test is not applicable for the argument (List<String>)
} 由于List<String>并不是Collection<Object>的子类(Collection<Object>并不是所有类型的集合的父类型),因此调用visit(list)会造成编译错误。为了解决这个问题,Java泛型引入了通配符“?”。Collection<?>是所有类型的集合的父类型,叫做“未知集合”。
需要注意的是,向“未知集合”中添加对象不是类型安全的,这会导致编译错误,唯一例外的是null。此外从“未知集合”中获得的对象的类型也只能是Object类型。例如:
Collection<?> c = new ArrayList<String>();
c.add("1"); // The method add(capture#1-of ?) in the type Collectoin<capture#1 of ?> is not applicable for the arguments (String)
c.add(null);
Object o = c.get(0);
5.1 有界通配符
5.1.1 上界
可以使用extends为通配符限定上界,例如以下代码中限定了通配符的上界是Base类:
public static void visit(Collection<? extends Base> c) {
for(Base b : c) {
System.out.println(b);
}
}
public static void main(String args[]) {
List<Base> list = new ArrayList<Base>();
list.add(new Base());
list.add(new Derived());
visit(list);
} 在visit方法中,同样不能向c中添加非null对象。例如以下代码会造成编译错误:
public static void visit(Collection<? extends Base> c) {
c.add(new Derived()); // The method add(capture#1-of ? extends Base) in the type Collection<capture#1 -of ? extends Base> is not applicable for the arguments(Derived)
} 有时也可以不使用通配符而达到相同的目的,例如:
public static <T> void copy(List<T> dest, list< ? extends T> src) {
...
}
public static <T, S extends T> void copy(List<T> dest, List<S> src) {
...
}
5.1.2 下界
可以使用super为通配符限定下界,考虑以下代码:
public class Derived extends Base implements Comparable<Object> {
public int compareTo(Object obj) {
return System.identityHashCode(this) - System.identityHashCode(obj);
}
public static <T extends Comparable<T>> T max(Collection<T> c) {
return Collections.max(c);
}
public static void main(String args[]) {
List<Derived> list = new ArrayList<Derived>();
list.add(new Derived());
Derived.max(list); // Bound mismatch: The generic method max(Collection<T>) of type Derived is not applicable for the arguments (List<Derived>). The inferred type Derived is not a valid substitute for the bounded parameter <T extends Comparable<T>>
}
} 以上的max方法中限定了T类型必须实现了Comparable<T>接口,那么在main方法中以list为参数调用max方法会导致编译错误,这是因为Derived类没有实现Comparable<Derived>接口。这样的限制有些严格,如果将max方法改成如下方式,可以带来更大的灵活性。
public static <T extends Comparable<? super T>> T max(Collection<T> c) {
return Collections.max(c);
} 以下的代码虽然没有太大的意义,但是需要注意的是,在print方法中,p.setFirst()方法和p.setSecond()方法的参数类型为T,但是p.getFirst()方法和p.getSecond()方法的返回值类型只能是Object型。
public class Pair<T> {
//
private T first;
private T second;
public Pair(T first, T second) {
this.first = first;
this.second = second;
}
public T getFirst() {
return first;
}
public void setFirst(T first) {
this.first = first;
}
public T getSecond() {
return second;
}
public void setSecond(T second) {
this.second = second;
}
public void print(Pair<? super T> p) {
Object first = p.getFirst();
Object second = p.getSecond();
System.out.println("first: " + first + ", second: " + second);
}
public static void main(String args[]) {
Pair<Derived> p1 = new Pair<Derived>(new Derived(), new Derived());
Pair<Base> p2 = new Pair<Base>(new Base(), new Base());
p1.print(p2);
}
}
5.2 通配符捕获
考虑为Pair类编写一个方法,用于交换first和second。由于通配符不是变量类型,那么如下的写法是非法的:
? t = p.getFirst(); 此外,以下的写法也会导致编译错误:
public static void swap(Pair<?> p) {
Object first = p.getFirst();
p.setFirst(p.getSecond()); // //The method setFirst(captur#4-of ?) in the type Pair<capture#4-of ?> is not applicable for the arguments (capture#5-of ?)
p.setSecond(first); // The method setFirst(captur#6-of ?) in the type Pair<capture#6-of ?> is not applicable for the arguments (Object)
} 可以通过一个额外的泛型方法中的类型参数来捕获通配符,例如:
public static void swap(Pair<?> p) {
doSwap(p);
}
private static <T> void doSwap(Pair<T> p) {
T first = p.getFirst();
p.setFirst(p.getSecond());
p.setSecond(first);
}
6 泛型和反射
Class类是泛型的,而且实现了java.lang.reflect.Type接口。Class类没有公共构造方法。Class对象是在加载类时由 Java 虚拟机以及通过调用类加载器中的 defineClass 方法自动构造的。Class类的newInstance方法通过默认的构造函数返回类型为T的对象。例如:
public static <T> Pair<T> make(Class<T> c) throws InstantiationException, IllegalAccessException {
return new Pair<T>(c.newInstance(), c.newInstance());
}
Pair<String> ps = Pair.make(String.class); 接口 TypeVariable<D extends GenericDeclaration>,ParameterizedType, WildcardType,GenericArrayType继承自Type,用于通过反射获得泛型类型的信息(尽管进行了擦除)。
TypeVariable 表示各种类型变量。其getName()方法返回在源码中声明的变量名;getBounds()方法返回类型变量上边界Type对象数组;getGenericDeclaration()返回GenericDeclaration对象,以表示声明此类型变量的一般声明。
ParameterizedType 表示参数化类型,例如Collection<String>。其getRawType()返回原始类型,也就是声明此类型的类或接口;getActualTypeArguments()方法返回表示此类型实际类型参数的 Type对象数组。
WildcardType 表示一个通配符类型表达式,如 ?、? extends Number 或 ? super Integer。getLowerBounds()方法返回类型变量下边界Type对象数组;getUpperBounds()方法返回类型变量上边界Type对象数组。
GenericArrayType 表示一种数组类型,其组件类型为参数化类型或类型变量。getGenericComponentType() 返回此数组的元素类型的Type对象。
关于以上接口的详细文档,请参考Javadoc。以下是一个简单的例子,用于获得类型变量的Class类型:
import java.lang.reflect.ParameterizedType;
public abstract class GenericBase<T extends Comparable<? super T>> {
//
private Class<T> clazz;
@SuppressWarnings("unchecked")
public GenericBase() {
ParameterizedType pt = (ParameterizedType)getClass().getGenericSuperclass();
clazz = (Class<T>)pt.getActualTypeArguments()[0];
}
public Class<T> getClazz() {
return clazz;
}
public void setClazz(Class<T> clazz) {
this.clazz = clazz;
}
}
public class GenericDerived extends GenericBase<String> {
public static void main(String args[]) {
GenericDerived gd = new GenericDerived();
System.out.println(gd.getClazz());
}
}
发表评论
-
fanxing
2009-07-29 11:22 12121.<? extends Class>是一种限制通 ... -
JAVA reflect
2009-07-29 10:21 1097Java 反射是Java语言的一个很重要的特征,它使得Java ... -
java常用的代码11
2009-07-29 10:19 724/** * 将某个日期以固定格式转化成字符串 ... -
java 常用的代码
2009-07-29 10:18 1064收集的java常用代码,共同分享(二) Java code ... -
超类(java)
2009-07-29 09:08 2776OO程序设计中最强大可能就是代码的重用,结构化设计从某种程度上 ... -
hibernate
2009-07-20 14:18 928转载:http://www.su ... -
spring Aop中动态代理
2009-07-16 15:53 3200Spring 缺省使用J2SE 动态 ... -
Spring BYName
2009-07-15 15:06 1193pring中autowire="byName&quo ... -
Spring框架与AOP思想
2009-07-15 12:57 905对Spring框架中所包含的A ... -
反向控制和面向切面编程在Spring的应用
2009-07-15 12:42 714针对传统的J2EE架构 ... -
java web 开发过程中常见的一些错误
2009-07-13 11:10 4201现在通常人们讨论和实现Java WEB应用时,往往过度关注框架 ...
相关推荐
标题中的“Java Generic 介绍”涵盖了泛型的基本概念、使用方式以及其背后的原理。以下是对这一主题的详细阐述: 1. **泛型的基本概念**:泛型是Java中的一种模板类或接口,它允许开发者在定义类、接口和方法时使用...
在Java编程语言中,泛型(Generic)是一个强大的特性,它允许我们在编译时检查类型安全,并且可以消除运行时的类型转换。泛型引入的主要目的是提高代码的重用性、安全性和效率,同时减少类型转换的繁琐工作。这篇...
本文将深入探讨Java中的浅复制和深复制,并以Android为背景,结合具体的实例讲解如何实现Java泛型深拷贝。 首先,我们要理解浅复制和深复制的概念。浅复制(Shallow Copy)是指创建一个新的对象,然后将原对象引用...
在《java-generic.rar》压缩包中包含的《java generic.pdf》文件,很可能是详细阐述了以下几个关于Java泛型的核心知识点: 1. **类型参数化**:泛型的核心在于类型参数化,这使得我们可以在定义类、接口和方法时...
【Japag - Java generic command line GUI 开源项目详解】 Japag,全称为 Java Application for Providing a Generic GUI,是一个开源项目,专为那些希望通过图形用户界面(GUI)而非命令行来运行各种命令行应用...
java高手真经 全光盘源代码 打包rar 第1部分(2个程序包) HelloWorld.zip 01.Java入门样例Hello...javageneric.zip 27.Java泛型编程 javaannotation.zip 28.Java注释符编程 javafeature.zip 29.Java5.0语言新特性
看到那些要积分的很不酸,发布免费版本。 第1部分(2个程序包) HelloWorld.zip 01.Java入门样例...javageneric.zip 27.Java泛型编程 javaannotation.zip 28.Java注释符编程 javafeature.zip 29.Java5.0语言新特性
看到很多人都分卷打包的,下载很是不方便,还浪费积分,我就整合压缩打包到一个包里面,里面包含全部...javageneric.zip 27.Java泛型编程 javaannotation.zip 28.Java注释符编程 javafeature.zip 29.Java5.0语言新特性
Java 泛型是Java SE 5.0引入的一项重要特性,极大地增强了代码的类型安全性和重用性。泛型接口是泛型在接口中的应用,它允许我们在接口中定义带有类型参数的方法,使得实现该接口的类可以使用不同的数据类型。下面...
标题中的"Generic_MT4_java_generic_mt4_"暗示了一个与MetaTrader 4 (MT4)交易平台相关的编程项目,可能是一个自定义的智能交易系统(Expert Advisor,EA)或指标,使用了Java语言,并且具有通用性。这个“Generic_...
Java中的泛型是Java SE 5.0引入的一项重要特性,极大地增强了代码的类型安全性和重用性。泛型方法是泛型概念的一个关键部分,它允许我们在方法签名中使用类型参数,从而使方法能够处理不同类型的参数。在这个“Java...
Java1.5泛型指南中文版(Java1.5 GenericTutorial)
此外,还介绍了一种名为 JGL (Java Generic Library) 的第三方库,该库在 Java Collection Framework 出现之前就已经存在,并且提供了一些额外的功能。 #### 八、总结 《Java Collection Framework》这本书不仅是...
### Java泛型的使用详细讲解 #### 一、引言 在Java开发中,泛型是一种重要的语言特性,它能够帮助开发者在不增加代码量的情况下处理多种数据类型,同时还能保持代码的清晰度和可读性。本文将详细介绍Java泛型的...