泛型是什么?它在java中又有哪些必要性?
Posted 守夜人爱吃兔子
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了泛型是什么?它在java中又有哪些必要性?相关的知识,希望对你有一定的参考价值。
1、什么是泛型?
对于大部分同学而言,泛型一词并不陌生,因为在Java开发中经常会用。常用的List、Map都用到过,所以泛型在Java中的重要的地位不言而喻。同时泛型也被广泛应用于面向对象编程和各种设计模式中。那么究竟什么是泛型,我们又为什么要用泛型?
下面我们通过一道测试题来为同学们做解释:
List<String> l1 = new ArrayList<String>();
List<Integer> l2 = new ArrayList<Integer>();
System.out.println(l1.getClass() == l2.getClass());
上面输出的结果是什么?懂泛型的同学肯定知道答案,就是true,因为这是典型地泛型类型擦除。
泛型是Java5才有的。在此之前,Java中的对象集合,往往是需要转换为Object对象,取出对象也是要再次进行强制类型转换,这样的操作带来了ClassCastException风险。泛型的加入,使得集合在编译阶段就可以推断出集合中元素类型,减少了代码臃肿和异常风险。
泛型的本质是为了参数化类型(在不创建新的类型的情况下,通过泛型指定的不同类型来控制形参具体限制的类型)。也就是说在泛型使用过程中,操作的数据类型被指定为一个参数,这种参数类型可以用在类、接口和方法中,分别被称为泛型类、泛型接口、泛型方法。
2、泛型的使用
定义类、接口或方法时使用类型形参(泛型),在声明变量、创建对象、调用方法时候会动态指定这个泛型。
2.1 泛型类
public class Apple<T> {
//使用T类型定义实例变量
private T info;
public Apple(){}
//使用T类型来定义构造器
public Apple(T info){
this.info = info;
}
public T getInfo() {
return info;
}
public void setInfo(T info) {
this.info = info;
}
}
//使用
Apple<String> name = new Apple<>("苹果");
Apple<Double> price = new Apple<>(.);
泛型类与普通类的区别就是在方法名后使用进行了声明泛型形参,接下来可以在类中将T作为类型使用(如上面直接定义变量info)。
2.2 泛型接口
//泛型形参E
public interface loadResult<E>{
//E 作为参数类型
void returnResult(E result);
}
public interface addResult<E>{
//E 作为类型使用
E add();
}
泛型接口跟泛型类声明基本一样,使用的范围也是相同。
2.3 泛型方法
List不是List子类,如果想要将每一个String类型的数组元素放到一个集合中,集合的数据类型只能是String:
String[] fruitArray = new String[]{"apple","banana","peach"};
List<String> fruitList = new ArrayList<>();
array2Collection(fruitArray,fruitList);
Log.d(TAG,">>>>>> fruitList = " + fruitList);
//代码省略...
private void array2Collection(String[] array, List<Object> list) {
for (String str : array) {
list.add(str);
}
}
比如上面的代码,在编译环境下就会报异常。所以如果后期需要放置Integer类型,就需要再次新建Integer的集合,这样的方法功能十分有限。
为了解决这个问题,Java设计了泛型方法。泛型方法对比普通方法多了泛型形参声明,所有的泛型形参声明放在修饰符和方法返回值中间。
修饰符 <T,S> 返回值类型 方法名(形参列表){
//方法体
}
private static <T> void add(T t) {
Log.d(TAG, ">>>>>>" + t + "-100");
}
使用泛型方法来完成将数组数据元素放到集合中
//定义一个泛型方法,T泛型形参仅可以在该方法中使用
private <T> void array2Collection(T[] array, List<T> list) {
for (T str : array) {
list.add(str);
}
}
//泛型方法使用
String[] fruitArray = new String[]{"apple", "banana", "peach"};
List<String> fruitList = new ArrayList<>();
Integer[] integers = new Integer[]{3};
Float[] floats = new Float[]{1.0f, 2.0f, 3.2f};
List<Number> numberList = new ArrayList<>();
array2Collection(integers, numberList);
Log.d(TAG, ">>>>>> Integer[] numberList = " + numberList);
array2Collection(floats, numberList);
Log.d(TAG, ">>>>>> Float[] numberList = " + numberList);
array2Collection(fruitArray, fruitList);
Log.d(TAG, ">>>>>> List<String> fruitList = " + fruitList);
//输出结果:
D: >>>>>> Integer[] numberList = [3]
D: >>>>>> Float[] numberList = [1.2.3.2]
D: >>>>>> List<String> fruitList = [apple, banana, peach]
3、泛型通配符
除了用 <T>
表示泛型外,我们还经常碰到 <?>
这种形式的泛型, ? 被称为通配符。
通常通配符的出现是为了指定泛型中的类型范围。通配符简分为 3 种形式:被称作无限定的通配符、被称作有上限的通配符、被称作有下限的通配符。
3.1、无限定通配符
无限定通配符经常与容器类配合使用,它其中的 ? 其实代表的是未知类型,所以涉及到 ? 时的操作,一定与具体类型无关。
public static void showShapes(List<?> shapeList) {
}
当 <?>
存在时,其实List 对象丧失了 add() 方法的功能,当调用时编译器不通过。
public static void showShapes(List<?> shapeList) {
shapeList.add(new Circle());//报错 ? cannot applied to Circle
}
<?>
提供了只读的功能,也就是它删减了增加具体类型元素的能力,只保留与具体类型无关的功能。它不管装载在这个容器内的元素是什么类型,它只关心元素的数量、容器是否为空。
3.2、上界通配符
上限通配符用于在方法中放宽对变量类型的限制。代表类型 T 及 T 的子类。
上面的方法改为:
public static void showShapes(List<? extends Shape> shapeList) {
for (Shape shape:shapeList){
Log.i(TAG,"shape="+shape.getShape());
}
}
showShapes(circleList);//可以运行
showShapes(triangleList);//可以运行
shapeList.add(null);//不报错
shapeList.add(new Circle());//报错 Shape cannot applied to Circle
可以对列表中的?对象进行操作了。但是,注意的是对于上界泛型列表,除空之外,我们不允许将任何对象添加到列表中。
3.3、下界通配符
上界泛型列表,无法添加对象,如果需要添加,可以用下界通配符实现。
public static void showShapes(List<? super Shape> shapeList) {
shapeList.add(new Circle());
shapeList.add(new Circle());
}
最后
对于程序员来说,要学习的知识内容、技术有太多太多,要想不被环境淘汰就只有不断提升自己,从来都是我们去适应环境,而不是环境来适应我们!
不用多说,相信大家都有一个共识:无论什么行业,最牛逼的人肯定是站在金字塔端的人。所以,想做一个牛逼的程序员,那么就要让自己站的更高,成为技术大牛并不是一朝一夕的事情,需要时间的沉淀和技术的积累。
现在竞争这么激烈,只有通过不断学习,提高自己,才能保持竞争力。
对于一些不知道学习什么,没有一个系统路线的程序员,这里给大家提供一些学习资料
需要的小伙伴,可以一键三连,点击这里获取免费领取方式!
《Java核心知识点合集(283页)》
内容涵盖:Java基础、JVM、高并发、多线程、分布式、设计模式、Spring全家桶、Java、MyBatis、ZooKeeper、Dubbo、Elasticsearch、Memcached、MongoDB、Redis、mysql、RabbitMQ、Kafka、Linux、Netty、Tomcat、数据库、云计算等
《Java中高级核心知识点合集(524页)》
《Java高级架构知识点整理》
《Docker从入门到实践》
《spring could 学习笔记》
《JVM与性能调优知识点整理》
《MySQL性能调优与架构设计解析文档》305页
《nginx入门到实战》319页
《Java并发编程》385页
《1000道 互联网Java工程师面试题 (485页)》
需要的小伙伴,可以一键三连,点击这里获取免费领取方式!
以上是关于泛型是什么?它在java中又有哪些必要性?的主要内容,如果未能解决你的问题,请参考以下文章