前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >泛型的继承和通配符,同时归纳集合部分的面试点

泛型的继承和通配符,同时归纳集合部分的面试点

作者头像
用户1153489
发布于 2018-01-12 08:43:35
发布于 2018-01-12 08:43:35
88600
代码可运行
举报
运行总次数:0
代码可运行

    在定义泛型时,我们可以通过extends来限定泛型类型的上限,也可以通过super来限定下限,这两个限定字一般会和?等关键字搭配使用。

    比如有这样的代码List<? super Father> dest,这里,super包含“高于”的意思,? Super Father就表示dest存放的对象应当“以Father为子类”;换句话说,在dest里,可以存放任何子类是Father类的对象。

    再来看个extends的用法。比如有这样的代码,List<? extends Father> src,extends用来表示继承,这里的src可以存放以”Father”为父类的对象;也就是说,src可以存放任何Father对象的子类。

    在实际的项目里,我们一般从List<? extends Father> src这类的集合里读元素,而从List<? super Father> dest这样的集合里写元素。通过下面的GenericExtends.java例子,再来了解extends,super和?的用法。    

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
1    import java.util.ArrayList;
2    import java.util.List;
3    //定义一个空的父类和空的子类
4    class Father{ }
5    class Son extends Father{}
6    //这是个包含main方法的主类
7    public class GenericExtends {
8       //这个方法里,将把src里的对象复制到dest里   
9       static void copy(List<? super Father> dest, 
10                        List<? extends Father> src) {  
11            for (int i=0; i<src.size(); i++)
12            {  dest.add(src.get(i));    }
13        }

    在第9行copy方法的两个参数里,我们看到了两个包含extends和super泛型的参数。在方法体的for循环里,我们的做法符合刚才讲到的原则:从带extends泛型的集合里读,往带super泛型的集合里写。   

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
14        public static void main(String[] args) {
15         Father f = new Father();
16            Son s = new Son();
17         //创建了一个带Father泛型的集合,并向其中放了一个元素
18            List<Father> srcFatherList = new ArrayList<Father>();
19            srcFatherList.add(f);        
20            List<Father> destFatherList = new ArrayList<Father>();
21         //通过copy方法,把元素复制进了destFatherList里
22            copy(destFatherList,srcFatherList);
23         //这里的输出是1,说明copy方法成功地往destFatherList里写了元素
24            System.out.println(destFatherList.size());        
25        }
26    }

    在定义方法的参数时,我们可以用带extends和super的泛型来确保输入参数类型的准确性。除此之外,这两种泛型的用处不大,比如在main函数的第22行里,调用copy方法时,我们传入的参数都是List<Father>类型。

    下面我们来展示些错误的用法:

    错误用法一:用带问号的类型实例化集合对象。   

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
1      List<?> list = new ArrayList<String>(); //正确
2     //List<?> list = new ArrayList<?>(); //错误

    第1行里,虽然在等号的左边我们用到了问号,但在右边,我们确立了泛型类型是String,这个是正确的。与之相比,在等号的左边和右边我们都用了问号,这是错误的,因为编译器不知道list集合该采用哪种泛型类型。

    错误用法二:向包含<? extends Father>泛型的集合里写。    

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
1    List<? extends Father> list = new ArrayList<Father>();
2    //list.add(f); //error

   第2行会报语法错,原因是编译器不知道这个基于Father的子类型究竟是什么;因为没法确定,为了保证类型安全,所以就不允许往里面加数据。

    错误用法三:从包含<? super Father>泛型的集合里读。   

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
1        List<? super Father> list1 = new ArrayList<Father>();
2        list.add(f); //正确
3        //list.get(0);//错误

   第3行会报语法错,原因是编译器不知道该用哪种Father的父类来接收get的返回值;于是,同样为了保证类型安全,所以就不允许读。

    从上述的第二和第三种错误的用法里,我们能感受到,extends和super这两种定义泛型的用法除了在定义方法参数之外,还真没其他合适的用途。    

    集合部分的面试点归纳:

    对于初级程序员或者是刚完成升级的高级程序员来说,应该能“合理地”使用集合,这个要求看似不难,其实不然,搞懂了当然不难。

    下面看些常见的面试题,并作相应的答疑。

    1 ArrayList和LinkedList有什么差别?在哪种场景里应当用ArrayList(或LinkedList)?

    大家如果学过数据结构,这个问题不难回答:前者是基于数组,数组比较擅长索引查找,但不擅长被频繁地插入或删除;后者是基于链表,它擅长被频繁地插入或删除,如果对其频繁地进行索引查找,就会影响性能。

    2 ArrayList和Vector有什么差别?

我们知道,ArrayList是线程不安全的,而且会以大概50%的规模进行动态扩容;而Vector是线程安全的,它会以100%的规模进行动态扩容。所以在单线程环境下,出于性能和内存使用量这两方面的考虑,建议使用ArrayList。

    3 我们知道,Set里不允许插入重复的元素。对于HashSet和TreeSet,如果我们要插入自定义的类,我们该往自定义的类里加入什么方法来保证“不重复”?

    对于HashSet,它是基于Hash表的,我们需要重写其中的hashCode和equals方法;对于TreeSet,我们需要重写compareTo方法(当然还得实现Compareable接口)。

    在大多数场景下,我们是会放入自定义类型,而不是简单数据类型。如果候选人不知道怎么回答,那么我就可以认定他只是“简单地用到了集合”,而不是“对集合有深入的了解”。

    4 在使用迭代器遍历集合对象时,我们能不能边访问边修改?如果这样做,会有什么问题?

    第一,会报异常,因为使用迭代器时不能边访问边修改;第二,这种异常其实是种保护机制,因为边遍历边修改会增加出错的机会;第三,如果确实需要这样做,可以使用CopyOnWriteArrayList之类的集合,或者干脆别通过迭代器来访问集合对象。

    5 在使用HashMap时,你有没有重写hashCode和equals方法,如果不重写,会有什么问题?如果候选人对此一脸雾水,那么我会给点提示:如果我们要在HashMap的Key部分放入自定义的类,而不是基本数据结构,那么我们该在这个自定义的类里重写什么方法?

    如果大家被问到这个问题,可以好好利用这个机会来展示你对此的深入了解。

    要点1,HashMap是基于hash表这个数据结构来实现的,所以其中的get或containsKey的效率相当高(接近于1)。

    要点2,描述一下Hash表的数据结构,重点说说如何通过hash算法把待存入的数据和存储位置绑定到一起了,同时还可以说出HashMap表里是通过链地址法来解决冲突。

    要点3,hashCode方法其实是对应hash表里的hash算法,由此我们可以计算出待存储元素的存放位置。如果我们不重写,将会用到Object里的hashCode方法,它是返回该对象的内存地址;而如果我们不重写equals方法,那么在冲突的情况下,就无法定位到具体的对象了。总之,如果不重写hashCode和equals方法,在调用containsKey和get方法时,就无法得到“看上去一致”的对象了。

    如果面试官(也包括笔者)看到应试者能清晰地说出上述的意思,就认为此人对技术细节非常了解,就有可能减少集合部分(或者乃至Java Core部分)的面试题。如果大家也是这样并在回答其它问题时不犯原则性的错误,那么也可能得到“对技术了解比较透彻”之类的好评。

    6 Collections和Collection有什么差别?

    Collections 是一个集合的一个类,其中包含有一些和集合操作相关的静态多态方法。Jave集合里则有另外一个和它非常相似的接口Collection(不带s),它是线性表类集合的父接口,List和Set等接口都是通过实现这个接口来实现的。

    7 你有没有用过T,?, super和extends这种泛型?

    说实在的,上述泛型在实际的项目里用得还真不多,你如果说没用过,面试官也不会难为你。不过大家可以结合3.5.1部分的知识点,向面试官说明你是怎么把泛型作用到类和方法上,也可以结合上文描述的copy方法向面试官说明? extends和? super的用法,如此面试官就会认为你对集合部分的知识掌握得很透彻。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2017-12-26 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
泛型
使用泛型可让编写的代码对多种不同类型的对象重用(笔者理解为与方法的重载互补),比如你希望某个方法foo() 可接收多种参数来进行处理而不用为这多个参数各写一个方法,当然可用Object作为参数,但使用Object作为方法参数有两个缺点:
晚上没宵夜
2022/05/09
5930
面试官问我:“泛型擦除是什么,会带来什么问题?”
其实我们很常见这个问题,你甚至经常用,只是没有去注意罢了,但是很不碰巧这样的问题就容易被面试官抓住。下面先来看一段代码吧。
ClericYi
2020/06/23
2.2K0
Java泛型中的通配符 T,E,K,V,?,你确定都了解吗?
Java 泛型(generics)是 JDK 5 中引入的一个新特性, 泛型提供了编译时类型安全检测机制,该机制允许开发者在编译时检测到非法的类型。
用户5224393
2019/09/05
1.6K0
Java泛型中的通配符 T,E,K,V,?,你确定都了解吗?
泛型的深入研究——面试时说出能加分
我们可以在定义集合时设置泛型这样的约束,也可以在定义类和方法时加上泛型,这样能提升类和方法的灵活性。此外我们还可以在定义泛型时加上继承和通配符。在平时的培训中,我曾发现初学者对一些复杂的泛型(其实也不复杂,只不过是较少用)感到困惑。这里就通过一些案例展示泛型在项目里的常见用法。
用户1153489
2020/02/18
4570
Java 基础面试题总结
hey guys ,这不是也到了面试季了么,cxuan 又打算重新写一下 Java 相关的面试题,先从基础的开始吧,这些面试题属于基础系列,不包含多线程相关面试题和 JVM 相关面试题,多线程和 JVM 的我放在后面了,下面不多说,搞起!
cxuan
2021/04/21
7340
Java 基础面试题总结
Java Review(三十一、泛型)
Java 集合有个缺点一一把一个对象"丢进"集合里之后,集合就会"忘记"这个对象的数据类型 ,当再次取出该对象时 , 该对象的编译类型就变成 了 Object 类型(其运行时类型没变) 。
三分恶
2020/07/16
7570
10 道 Java 泛型面试题
  1. Java中的泛型是什么 ? 使用泛型的好处是什么?   这是在各种Java泛型面试中,一开场你就会被问到的问题中的一个,主要集中在初级和中级面试中。那些拥有Java1.4或更早版本的开发背景
java达人
2018/01/31
60.7K4
【java筑基】吃透泛型(一万字长文,建议收藏)
集合元素过去默认为Object类型,无法指定元素类型,编译时不检查类型,而且每次取出对象都要进行强制类型转换,泛型出现避免了这种臃肿的代码。下列代码会看到编译时不检查元素类型导致的异常。
半旧518
2022/10/26
4370
【java筑基】吃透泛型(一万字长文,建议收藏)
Java基础(二十):泛型
冬天vs不冷
2025/01/21
1540
Java基础(二十):泛型
【Java数据结构】泛型的进阶部分(泛型通配符)
思考:那既然 ArrayList<? extends Number> 可以代表 ArrayList< Integer > 或 ArrayList< Float >,为什么不能向其中加入 Integer、Float 等对象呢?
E绵绵
2024/09/12
1060
【Java数据结构】泛型的进阶部分(泛型通配符)
Java的“泛型”特性,你以为自己会了?(万字长文)
使用Java的小伙伴,对于Java的一些高级特性一定再熟悉不过了,例如集合、反射、泛型、注解等等,这些可以说我们在平时开发中是经常使用到的,尤其是集合,基本是只要写代码没有用不到的,今天我们先来谈谈泛型。
小灰
2022/09/01
4370
Java的“泛型”特性,你以为自己会了?(万字长文)
聊聊JDK泛型那些事儿
在Java SE 1.5之前,没有泛型的情况的下,通过对类型Object的引用来实现参数的“任意化”,“任意化”带来的缺点是要做显式的强制类型转换,而这种转换是要求开发者对实际参数类型可以预知的情况下进行的。对于强制类型转换错误的情况,编译器可能不提示错误,在运行的时候才出现异常,这是一个安全隐患。 
孟君
2019/08/28
3730
聊聊JDK泛型那些事儿
每日一道Java面试题:说一说Java中的泛型?
今天的每日一道Java面试题聊的是Java中的泛型,泛型在面试的时候偶尔会被提及,频率不是特别高,但在日后的开发工作中,却是是个高频词汇,因此,我们有必要去认真的学习它。
JavaBuild
2024/05/27
1020
每日一道Java面试题:说一说Java中的泛型?
搞明白 Java 的通配符泛型
Java 泛型中的通配符泛型问题困扰我很久,即 <? super T> 和 <? extends T> 和 <?> 这几种泛型,到底是什么,到底怎么用。从含义上理解, super 是指 T 和 T 的
卢衍飞
2023/02/16
5390
《Kotlin 极简教程 》第6章 泛型
通常情况的类和函数,我们只需要使用具体的类型即可:要么是基本类型,要么是自定义的类。
一个会写诗的程序员
2018/08/17
1.8K0
Java泛型中的细节
学习Java,必不可少的一个过程就是需要掌握泛型。泛型起源于JDK1.5,为什么我们要使用泛型呢?泛型可以使编译器知道一个对象的限定类型是什么,这样编译器就可以在一个高的程度上验证这个类型消除了强制类型转换,使得代码可读性好,而这个过程是发生在编译时期的,即在编译时期发现代码中类型转换的错误所在,及时发现,而不必等到运行时期抛出运行时期的类型转换异常。
w4ngzhen
2023/10/16
2960
一文打通java泛型
集合容器类在设计阶段/声明阶段不能确定这个容器到底实际存的是什么类型的对象,所以在JDK1.5之前只能把元素类型设计为Object,JDK1.5之后使用泛型来解决。因为这个时候除了元素的类型不确定,其他的部分是确定的,例如关于这个元素如何保存,如何管理等是确定的,因此此时把元素的类型设计成一个参数,这个类型参数叫做泛型。Collection,List,ArrayList 这个就是类型参数,即泛型
一个风轻云淡
2023/10/15
1900
一文打通java泛型
第十八天 集合-泛型&list接口&set接口【面试+工作】
泛型的使用:一般在创建对象时,将未知的类型确定具体的类型。当没有指定泛型时,默认类型为Object类型。
Java帮帮
2018/07/26
7880
第十八天 集合-泛型&list接口&set接口【面试+工作】
Java泛型深入理解「建议收藏」
在面向对象编程语言中,多态算是一种泛化机制。例如,你可以将方法的参数类型设置为基类,那么该方法就可以接受从这个基类中导出的任何类作为参数,这样的方法将会更具有通用性。此外,如果将方法参数声明为接口,将会更加灵活。
全栈程序员站长
2022/09/10
8620
java泛型通配符 ? extends T 和 ? super T 的区别和用法
1.二者的意思 ? extends T :表示上界是T, ? 都是继承自T的,都是T的子类; ? super T :表示下界是T,?都是T的父类; 2.用法 例1,我们有多个对象,其中Cat,Do
IT云清
2019/01/22
1.8K0
相关推荐
泛型
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档