当前位置: 首页 > 科技观察

Java中天天用的一个知识点,却不知道为什么

时间:2023-03-19 14:41:05 科技观察

泛型是Java天天用的一个特性,你真的知道它的原理吗?什么是泛型首先,让我们谈谈什么是泛型。泛型是广义类型,即广义参数类型。通常我们在写代码的时候,都会定义方法的参数来指定具体的类型,比如Integer、Double或者其他自己写的类。那么广义类型就是我们在写方法的时候,不指定参数的类型,而是定义一个通用类型,使用的时候会根据类型自动进行转换。上面的描述可能比较抽象,我们再来看看,如果没有泛型会怎样,为什么天天用这个泛型。原理我们都知道ArrayList是Java中经常使用的集合。是一个变长数组,底层是基于Object[]实现的。可以简单理解为如下内容当我们使用上面的ArrayList如果是存储String类型,需要进行如下操作,使用时必须进行手动转换。ArrayListlist=newArrayList();list.add("Java");list.add("C++");Stringfirst=(String)list.get(0);Stringfirst=(String)list.get(1);先看当你看上面的代码时,每个人都会感到惊讶。如果每次用强制转移都这样显示,那岂不是要命?而且,只有当用户知道是什么情况时,才可以进行手动强制转移。如果没有当你知道是什么类型的时候,就没有办法进行强制转移。这种方法简直让人受不了,而且特别容易出错。那么如何解决这个问题呢?有朋友说我们可以针对不同的类型实现自己的ArrayList类,这样我们在使用的时候就不用勉强了。对此,阿芬只能说,对于JDK提供的类可以做到这一点,但是对于用户自己编写的类又如何实现呢?这时候你可能会说,我天天用ArrayList,也没手动强制过。还是用的好。这要归功于我们今天要说的主角,泛型。我们在ArrayList中加入的泛型,通过定义一个泛化类型,当我们使用它的时候,如果传递的类型不是指定的类型,那么在编译阶段就会报错,所以就不需要强行操作了.publicclassArrayList{privateObject[]array;//任何类型都是Object的子类,所以这里还是不改privateintsize;publicvoidadd(Ee){...}publicvoidremove(intindex){...}publicEget(intindex){...}}这样修改之后,我们就可以做ArrayListstrList=newArrayList();list。add("Java");list.add("C++");Stringfirst=list.get(0);//这里不用强传Stringfirst=list.get(1);//不用在这里强制调用list.add(newInteger(100));//编译报错当我们需要使用Integer对象时,可以使用如下方法ArrayListlist=newArrayList();list.add("Java");//编译错误list.add("C++");//编译错误list.add(newInteger(100));//编译通过另外,我们还知道ArrayList实现了List接口,如下图,所以会有一个向上转型的概念,就是我们使用List我们前面定义的时候也是可以的,也就是我们通常的定义方式,即Listlist=newArrayList<>();但是这里需要注意不要进行下面的泛型向上变换,比如下面的例子。我们定义了Person类、Man类和Women类这。age=age;}}publicclassManextendsPerson{...}publicclassWomenextendsPerson{...}我们只能在使用ArrayListmanList=newArrayList();ListmanList1=newArrayList<>()时这样做;ArrayListwomenList=newArrayList();ListwomenList1=newArrayList<>();不可能ArrayListmanList=newArrayList();//这个转换是不允许的ArrayListpersonList=manList;personList.add(newMan());//打破了原来只有Man可以的约定存储personList.add(newWomen());因为我们不能在List中同时添加man和manwoman,这是不可接受的。接下来,我们再来看一个问题。假设我们有一个打印PersonList内容的方法,如下所示:publicvoidprint(ArrayListpersonList){for(Personp:personList){System.out.print(p.name);}}ArrayListmanList=newArrayList();list.add(newMan());list.add(newMan());print(manList);以上内容会编译出错,效果是这样的。原因是Man类虽然继承了Person类,但是ArrayList没有继承ArrayList类,所以这个方法无法通过编译。看到这里,朋友又是一愣。这是行不通的。不能引入泛型,那么多态就不支持了,这怎么办。这里还需要介绍一个东西,就是泛型中的extends。我们改一下print方法,这样此时编译就不会失败了。如下图,extends的意思是只要传入的参数是Person的子类,也可以支持多态。那么现在小伙伴们知道为什么会有很多JDK源码和很多框架的源码了吗?extendsxxx形式的代码对吧?