泛型
以下java.util.ArrayList类部分代码:
public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable {
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
}
如果未指定泛型<E>,那么默认类型就是Object类型。
ArrayList arrayList = new ArrayList();
arrayList.add(1);
arrayList.add(1.2);
arrayList.add("tom");
arrayList.add('a');
for (Object object : arrayList) {
System.out.println(object);
}
如果指定泛型<E>为String类型,那么在编译时所有的<E>都会替换成String类型。
public class ArrayList<String> extends AbstractList<String> implements List<String>, RandomAccess, Cloneable, java.io.Serializable {
public boolean add(String e) {
ensureCapacityInternal(size + 1);
elementData[size++] = e;
return true;
}
}
如果使用add方法参数不是String类型,编译时会报错:
ArrayList<String> arrayList = new ArrayList<>();
arrayList.add("abc");
arrayList.add("123");
arrayList.add(1); // 编译报错
自定义带有泛型的类
public class GenericClass<T> {
private T t;
public T getT() {
return t;
}
public void setT(T t) {
this.t = t;
}
}
GenericClass<T>此处的<T>是泛型的标识符,相当于是定义,或理解为形参。
同时,定义了一个成员变量t类型为T,以及变量t的Getter/Setter方法。
public class Test {
public static void main(String[] args) {
GenericClass genericClass = new GenericClass();
genericClass.setT("Hello Generic!");
Object t = genericClass.getT();
System.out.println("t = " + t);
}
}
不为泛型<T>指定类型时,默认是Object,因此,setT(Object o)是可以接受String类型参数的。
若指定了泛型的类型,那么
public class Test {
public static void main(String[] args) {
GenericClass<Integer> genericClass = new GenericClass<>();
genericClass.setT(100);
Integer t = genericClass.getT();
System.out.println("t = " + t);
}
}
setT(Object o)只能接受Integer类型以及子类类型。
自定义带有泛型的方法
public class GenericClass {
public static <T> T get(T x) {
return x;
}
}
在方法的修饰符后,定义或声明泛型标识符<T>,使用案例:
String string = GenericClass.get("Hello World");
Integer integer = GenericClass.get(100);
Double doubler = GenericClass.get(256.88);
一旦,参数赋值后,类型就确定了。
自定义带有泛型的接口
public interface GenericInterface<T> {
void method(T t);
}
若实现类不指定泛型类型:
public class GenericImpl implements GenericInterface {
@Override
public void method(Object o) {
// TODO
}
}
method方法里的泛型T被替换成了Object类型;如果指定了泛型呢?
public class GenericImpl implements GenericInterface<String> {
@Override
public void method(String s) {
}
}
method方法里的泛型T被替换成了String类型!
泛型通配符
当不知道要使用什么类型接收的时候,可以用泛型通配符<?>来表示:
public class Test {
public static void main(String[] args) {
List<String> strings = new ArrayList<>();
List<Integer> integers = new ArrayList<>();
GenericClass.printList(strings);
GenericClass.printList(integers);
}
}
比如,有个静态方法printList需要接收一个List类型的对象,要求传入List类型的参数泛型是String或者Integer类型,两者都可以。
那么就可以使用泛型通配符来实现:
public class GenericClass<T> {
public static void printList(List<?> list){
for (Object o : list) {
System.out.println("o = " + o);
}
}
}
如果,需求是传入的参数List<?> list只能是java.lang.Number类或子类的类型呢?我们可以限制参数中的泛型:
public class GenericClass<T> {
public static void printList(List<? extends Number> list){
// todo
}
}
上限限定extends Number 泛型类型只能是Number的子类或Number类型。
下限限定super Number 泛型类型只能是Number的父类或Number类型。
泛型通配符总结:常用在参数位置和返回值位置,在不清楚传入的参数类型中的泛型或者返回值类型中的泛型是什么类型时,就可以用泛型通配符<T>来代替。
博客围绕泛型展开,介绍了自定义带有泛型的类、方法和接口。未指定泛型时默认类型有规则,指定后编译时会替换。还阐述了泛型通配符,在不清楚参数或返回值泛型类型时使用,有上限、下限限定。
2461

被折叠的 条评论
为什么被折叠?



