Java_泛型—generic

泛型,在我们日常的Java编程中是很常见的,例如List<String> list = new ArrayList<String>(); 这句代码中,String就是泛型

泛型的本质:参数化类型,也就是说所操作的数据类型被指定为一个参数。

这句话怎么理解呢?说到参数,那就得说方法,我们经常定义方法的时候是不是要传固定的参数类型,可以理解为参数类型不固定了,在执行方法的时候才确定方法的参数类型。

看到这里肯定不好理解,往下看吧!

泛型的由来,先看一段代码:


说明:来来来,先看看代码:line11-17 是引入泛型之前,line20-24 是引入泛型之后的

接下来解释一下,看看这两段代码有什么区别?

1:在没引入泛型之前,List中,什么类型都可以存进去(其实都以Object的类型存进去的),而加入泛型之后,就只能添加泛型指定的类型了。看line22,当你往List中添加int类型的数据的时候就会报错。

2:在引入泛型之前,我们取出来的数据都是Object,那么当我们要使用的时候就要强转成我们当初存进去的类型,看line16;而引入泛型之后,我们就不用对取出来的数据进行强制转换,可以直接使用了。看line24。

3:安全性问题:可以尝试一下,把line20-24先注释掉,点击以下运行,就会出现ClssCastException(类型转换异常),提示我们不能将Int类型强制转换成String,再来看看这段代码中报错的那行,line22,其实报的就是同一种错误,只不过line22在编译的时候报错了,而line17是在运行的时候出错了,这就很简单了,其实就是将可能出现的错误在编译的时候能够及时的发现,在运行的时候就可以尽量的减少程序的错误;

总结:泛型的好处1:避免了强转的麻烦;2:解决了安全性的问题(将运行时可能出现的异常转移到了编译的时候)。


泛型的使用:集合,这无疑是最常见的,当我们定义一个List的时候,一般都会指定这个集合要存储的对象的类型-->泛型。


泛型的类型:

泛型可以定义在中,也可以定义在方法中,还可以定义在接口中。


泛型定义的位置

类和接口:定义在类名的后面,例如:class Animal<X> {}

方法:在修饰符后面,方法返回值的前面,例如:public <X> get(){}


下面来看看泛型定义在类中


看代码line12:泛型类定义的开始。这里定义了一个Printer类,同时定义了一个泛型X(X只是泛型的代表,可以使用任意的字母,例如:T,E,等都可以)

line13:声明一个泛型的变量mX

line15:类的构造方法

line19:一个打印方法,方法里面就是对泛型类型进行简单的输出,在控制台上打印出来;

最后看一下line6-7:这两行是对定义的泛型类的使用,定义类的时候泛型是放在类名后面的,所以使用的时候也一样,放在类名的后面。然后看line6后半句,new Printer类的时候传入一个String类型的数据,这个很好理解,构造方法中需要传入的是一个泛型类型的数据,你在声明的时候已经指定泛型是Sring,那么你这里也就相应的传入String类型的数据,同理:如果你在泛型中指定的是Integer,那么你这里就相应的传入int类型的数据;


看完了泛型的类,接下来我们看看泛型定义在方法中

看代码:现在的代码清爽很多了。line12-20是整个自定义的一个类,类中并不涉及到泛型,只是在print方法中定义了一个泛型X,同时,方法需要传一个泛型类型的数据,最后是打印,就这么简单。再看看line6-7:line6是不是没有泛型了,line7中也不见了泛型的踪影,这去哪了呢?其实很简单,在方法执行的时候会去检测一下传进去的类型的数据,然后再执行方法体。


来来来,我们对泛型进行一下小小的升级改造,还是看代码:


代码中。我们不仅把泛型定义在了类中。也定义在了方法(print2)中,然后再看看line8-9,可以看出,泛型方法是不受泛型类的限制的。有兴趣的可以尝试一下,将我这个小例子升级一下,在print2方法升级一下,写一个print3,print3中既有泛型类中的泛型,又有泛型方法中的泛型,看看咋样。嘿嘿。

既然泛型可以定义在方法中,那么泛型是不是也可以定义在静态方法中呢?

对,没错,泛型也可以定义在静态方法中,看代码:


代码就不过多的解释咯,一看就明白。但有一点要说明的是:泛型定义在方法的修饰符的后面,返回值类型的前面,这个位置是不变的,不论你前面有多少个修饰符,都是一样的,位置很重要,不信你可以试试定义在其他地方试试看!


泛型类和泛型方法都讲完了,该讲讲泛型定义在接口上了,接口也是类,人家也是一个java文件,对吧,为什么你不在介绍完类后介绍接口呢?你觉得一个接口中不定义方法的话,你觉得这个接口还有什么用?对吧。不对不对,你可以将泛型定义在类中,不定义在方法中啊?我问你是不是傻,既然定义在类中了,你方法中没使用这个泛型,你觉得有用么?没用的话,你定义泛型干嘛?对吧。

下面还是看代码:


看代码line11-13:定义了一个名字为Print的接口,接口中带一个泛型的参数。然后line12定义一个print的抽象方法,方法中需要传入一个泛型类型的参数;

接下来看line15-21:这是接口Print的实现类。这里指定了泛型的类型是String,然后你可以使用ec的自动生成代码的功能,让他自动生成,然后你会发现,自动生成的代码中,print方法中参数类型自动会定义成这个泛型,没错,就是这样。你外面定义的是什么,里面定义的也就是什么。

最后看一下ling6-7,line6中,定义了一个PrintImpl类对象,你会发现,我们定义这个类中是没有泛型的,不用像前面那样,要定义一个泛型进去,这很简单嘛。你在实现类里面已经指定泛型就是String,还需要再指定嘛?继续看line7,ling7中,你把传进去的数据删掉,你就会发现,它会自动提示你需要传一个String类型的数据,这也很好理解嘛。你line18中的方法中需要的是String,我这边肯定也就是String啦。


看完这段代码接下来看看升级版:


这个有设么区别呢?区别肯定是有的,这个和上面那个相比,这个更加灵活,我们在接口的实现类中没有指定相应的泛型类型,再看ling6,在使用的时候再去指定泛型的类型,这灵活度跟上面那个就有千差万别了,在这里,你可以再new一个对像,泛型的类型指定为Integer类型,然后再print方法中相应的传入int类型的数据。很灵活吧,再去看看前面那个,能做到传int类型的数据么?不是不可以,你需要再写一个改接口的实现类而已,哈哈!


从上面的例子可以看出,泛型使用的范围和方法参数使用的范围很相似。当泛型定义在类(接口)中的时候,泛型在整个类(接口)中是有效的,当泛型定义在方法中,泛型在整个方法中是有效的。


泛型的类,方法,接口都看完了,接下来我们看看泛型的高级应用:

通配符:?

通配符在java中是很常用的,在泛型中,也有通配符的存在,接下来还是看代码


还是Printer的例子,不同的是,我把print方法抽取出来了。然后添加一个get和set,来获取和设置要打印的数据。

接着看line12-14,print方法,打印方法中需要传入一个Printer,line13,输出打印者要打印的数据。其中,line12中,<>里面的不再是具体的类型(String,Integer,等等)也不是泛型,而是一个通配符?。可以理解为,不知道里面是什么类型,来什么是什么。如果比较难理解的话,可以看下面这段代码:


先看line15和line19的这两个方法的代码。然后再看line6-9,现在清楚了吧。清楚就往下看,看line24,这个方式其实就是前面line15和19这两个方法的合并,加入泛型之后合并成一个方法了,再看line11和12,是不是可以正常的调用这个方法,这就对了嘛,泛型不就体现出来了么。然后接着看上面那段有占位符?的代码,有占位符的方法和这段代码中的line24有啥区别?看看就明白咯。


接下来看看泛型的上限和下限

上面那个例子,不是没有对通配符?做限制么。来什么就是什么,现在我们要对它进行限制,也就有了上限和下限,上限,很简单嘛,就是规定了最大的那个,下限,就是规定最小的那个,暂且先这么理解呗。

看代码:


这个例子中,除了printer以外,还有3个类,分别是Animal,Cat,Dog三个类,他们三个的关系如右,Cat和Dog都是继承子Animal的。

接下来看代码line7-9,这三行代码不多的解释,然后看line10-12,这三行代码调用print方法进行打印动物,可以看到,既可以打印Animal,也可以打印Cat和Dog,然后再来看看line20的print方法,print方法中,我们可以看到,对泛型T做了限制,规定了T的上限Animal,也就是说,只能够接收Animal和Animal的子类,刚好Cat和Dog都是继承自Animal,这不就对了么,它只能接收Animal和其子类,信不信?不信你可以new一个Printer,然后里面的泛型为String或其他类型(反正不能是Animal的子类),然后调用print方法的时候传入这个printer,看看会不会报错,答案是肯定的。最后,看看line24的那个方法,这个方法和line20的在功能上是没设么区别的,只是写法不一样,一个用通配符表示而已。

这就是泛型的上限,那下限呢?

上限都搞清楚了,下限就很简单了嘛,跟extends相对应的关键字是神码?答案是:super

没错,上限就是只需要把extends改成super即可。

例子我就不再写了,直接将 line24中的 extends 改成 super ,然后你可以看到,line 15 和line16就报错了,这很容易解释嘛,上限是规定可以使用自身及其子类,那么下限就是规定了可以使用其自身和其父类嘛,Cat和Dog是Animal的子类,而不是Animal的父类,所以就报错咯,就这么简单,别急别急,先别急着删代码嘛,我们再把line24中的Animal改成Cat,你会发现,现在只剩下line16报错了。line15不报错了,这下彻底明白了吧!


OK,泛型就写到这里!


如果你觉得这篇文章写的好就点个赞呗,如果觉得写的不好就指点一二呗。小弟我也是刚入门的。谢谢!



  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值