梳理Java中关于泛型的知识

泛型

以下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>来代替。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值