【Java基础】泛型

泛型是什么

专业术语就不描述了,直接百度百科一下

泛型是程序设计语言的一种特性。允许程序员在强类型程序设计语言中编写代码时定义一些可变部分,那些部分在使用前必须作出指明。各种程序设计语言和其编译器、运行环境对泛型的支持均不一样。将类型参数化以达到代码复用提高软件开发工作效率的一种数据类型。泛型类是引用类型,是堆对象,主要是引入了类型参数这个概念。

泛型的关键字就是类型参数,看一下List接口的定义

public interface List<E> extends Collection<E>

<E>就是类型参数,当要使用的时候需要传入一个类型,想想方法的形参就明白了。

在jdk1.5之前是没有泛型的,那时的List是这样的

public class Demo1 {
    public static void main(String[] args) {
        List list = new ArrayList();
        list .add(new Animal());
        Animal animal = (Animal) list.get(0);
    }
}
class Animal{}

animal对象放进list集合,取出来时还要去强转,代码看着不直观也不美观,而且什么都可以往集合里丢,什么都往里面丢就等于什么都没往里面丢

于是,jdk1.5增加了泛型来限制List只存某一个类型

        List<Animal> list = new ArrayList<>();
        list.add(new Animal());
        Animal animal = list.get(0);

这样代码就比较直观,不需要强转,ArrayList<Animal >菱形中的Animal是可以省略的,因为List<Animal>已经声明了

当然不一定是List,任意类或者接口都可以定义类型参数

class Animal<T>{
    T t;
}

T就是Animal类的类型参数,当然这里也可以用任意字符来表示,可以是ABCDEFG,只是个参数,就像方法名的参数你可以随意取

泛型类也可以被继承,例子如下

1.class Dog<T> extends Animal<T>{} //正确
2.class Dog extends Animal<T>{} //错误
3.class Dog extends Animal{} //正确
4.class Dog extends Animal<String>{} //正确

第2种为什么错了呢?因为定义的Dog类没有指定泛型而Animal父类有泛型,当创建Dog对象时无法确定父类Animal的T到底是什么类型,所以会报错

类型通配符

将一个问号作为类型实参传给List,写作:List<?>,意思是未知类型元素的List,这个问号?被称为通配符,注意这里是类型实参,所以通配符是在使用而不是定义的时候用的

    public static void test(List<?> list){
    }

这里的List<?>代表可以传任何List泛型类,有人说可以用List<Object>吗,答案是不行,因为ArrayList<String> 并不是List<Object>的子类,那既然问号代表可以传任意List泛型子类,那么用类型参数不也可以吗,于是就有了泛型方法的定义

public static <T> void test(List<T> list){}

static <T> void修饰符和返回值之间定义<T>
既然说两者的作用是一样的,那泛型方法又有什么不同呢

    public static <T> void copy(List<T> src, List<T> dest){
        T t;
       for (int i=0; i<src.size(); i++){
           t = src.get(i);
           dest.add(t);
       }
    }

这里的T是可以直接用的,而?则没办法达到这个效果,还有一点是确保了src和dest集合里元素一致,也就是src和dest有依赖性的时候就需要用泛型方法

       List<Integer> src = new ArrayList<>();
       List<Integer> dest = new ArrayList<>();
       copy(src, dest);

按理说要将src集合中的元素拷贝到dest,dest集合只要是Integer的父类就都可以,所以copy泛型方法又可以这样写

   public static  <T> void copy(List<T> src, List<? super T> dest){
        T t;
       for (int i=0; i<src.size(); i++){
           t = src.get(i);
           dest.add(t);
       }
    }

     List<Integer> src = new ArrayList<>();
     List<Number> dest = new ArrayList<>();
     copy(src, dest);

List<? super T>代表了T的父类(T的上限),相反List<? extends T>代表了T的子类(T的下限),copy方法又可以这样写

    public static  <T> void copy(List<? extends T> src, List<T> dest){
        T t;
       for (int i=0; i<src.size(); i++){
           t = src.get(i);
           dest.add(t);
       }
    }
     List<Integer> src = new ArrayList<>();
     List<Number> dest = new ArrayList<>();
     copy(src, dest)

既然能达到同样的效果,那这两种的区别在哪呢,答案是角度问题

<? super T> 代表T是子类,<? extends T>代表T是父类,如果copy方法的返回值是src的一个元素,那么就得以src为中心。好了,以上就是泛型的全部内容,如有不妥之处欢迎指出
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值