java泛型

1:问:什么是 Java 泛型中的限定通配符和非限定通配符?有什么区别?

答:限定通配符对类型进行限制,泛型中有两种限定通配符,一种是 <? extends T> 来保证泛型类型必须是 T 的子类来设定泛型类型的上边界,另一种是 <? super T> 来保证泛型类型必须是 T 的父类来设定类型的下边界,泛型类型必须用限定内的类型来进行初始化,否则会导致编译错误。非限定通配符 <?> 表示可以用任意泛型类型来替代,可以在某种意义上来说是泛型向上转型的语法格式,因为 List<String> 与 List<Object> 不存在继承关系。

2:问:简单说说 List<Object> 与 List 原始类型之间的区别?

答:主要区别有两点。

原始类型和带泛型参数类型 <Object> 之间的主要区别是在编译时编译器不会对原始类型进行类型安全检查,却会对带参数的类型进行检查,通过使用 Object 作为类型可以告知编译器该方法可以接受任何类型的对象(比如 String 或 Integer)。

我们可以把任何带参数的类型传递给原始类型 List,但却不能把 List<String> 传递给接受 List<Object> 的方法,因为会产生编译错误。

3:问:简单说说 List<Object> 与 List<?> 类型之间的区别?

答:这道题跟上一道题看起来很像,实质上却完全不同。List<?> 是一个未知类型的 List,而 List<Object> 其实是任意类型的 List,我们可以把 List<String>、List<Integer> 赋值给 List<?>,却不能把 List<String> 赋值给 List<Object>。譬如:

22.png

所以通配符形式都可以用类型参数的形式来替代,通配符能做的用类型参数都能做。 通配符形式可以减少类型参数,形式上往往更为简单,可读性也更好,所以能用通配符的就用通配符。 如果类型参数之间有依赖关系或者返回值依赖类型参数或者需要写操作则只能用类型参数。

4:问:List<? extends T>和List <? super T>之间有什么区别?

答:有时面试官会用这个问题来评估你对泛型的理解,而不是直接问你什么是限定通配符和非限定通配符,这两个 List 的声明都是限定通配符的例子,List<? extends T> 可以接受任何继承自 T 的类型的 List,而 List<? super T> 可以接受任何 T 的父类构成的 List。例如 List<? extends Number> 可以接受 List<Integer> 或 List<Float>。Java 容器类的实现中有很多这种用法,比如 Collections 中就有如下一些方法:

33.png

5:问:说说 <T extends E> 和 <? extends E> 有什么区别?

答:它们用的地方不一样,<T extends E> 用于定义类型参数,声明了一个类型参数 T,可放在泛型类定义中类名后面、接口后面、泛型方法返回值前面。 <? extends E> 用于实例化类型参数,用于实例化泛型变量中的类型参数,只是这个具体类型是未知的,只知道它是 E 或 E 的某个子类型。虽然它们不一样,但两种写法经常可以达到相同的目的,譬如:


11.png

6:问:说说 List<String> 与 List<Object> 的关系和区别?

答:这两个东西没有关系只有区别。

因为也许很多人认为 String 是 Object 的子类,所以 List<String> 应当可以用在需要 List<Object> 的地方,但是事实并非如此,泛型类型之间不具备泛型参数类型的继承关系,所以 List<String> 和 List<Object> 没有关系,无法转换。

7:问:请说说下面代码片段中注释行执行结果和原因?

111.png

答:上面代码段注释行执行情况解释如下。

三个 add 方法都是非法的,无论是 Integer,还是 Number 或 Object,编译器都会报错。因为 ? 表示类型安全无知,? extends Number 表示是 Number 的某个子类型,但不知道具体子类型, 如果允许写入,Java 就无法确保类型安全性,所以直接禁止。

最后方法的 add 是合法的,因为 <? super E> 形式与 <? extends E> 正好相反,超类型通配符表示 E 的某个父类型,有了它我们就可以更灵活的写入了。

本题特别重要:一定要注意泛型类型声明变量 ?时写数据的规则。

8:问:请说说下面代码片段中注释行执行结果和原因?

222.png

答:上面代码编译运行情况如注释所示,本题主要考察泛型中的 ? 通配符的上下边界扩展问题。

通配符对于上边界有如下限制:Vector<? extends 类型1> x = new Vector<类型2>(); 中的类型1指定一个数据类型,则类型2就只能是类型1或者是类型1的子类。

通配符对于下边界有如下限制:Vector<? super 类型1> x = new Vector<类型2>(); 中的类型1指定一个数据类型,则类型2就只能是类型1或者是类型1的父类。

9: 问:下面程序合法吗?

333.png

答:编译时报错,因为 Java 类型参数限定只有 extends 形式,没有 super 形式。

10: 问:下面程序有什么问题?该如何修复?

444.png

答:语句 printCollection(listInteger); 编译报错,因为泛型的参数是没有继承关系的。修复方式就是使用 ?通配符,printCollection(Collection<?> collection),因为在方法 printCollection(Collection<?> collection) 中不可以出现与参数类型有关的方法,譬如 collection.add(),因为程序调用这个方法的时候传入的参数不知道是什么类型的,但是可以调用与参数类型无关的方法,譬如

collection.size()。

11:问:请解释下面程序片段的执行情况及原因?

555.png

答:t0 编译直接报错,add 的两个参数一个是 Integer,一个是 Float,所以取同一父类的最小级为 Number,故 T 为 Number 类型,而 t0 类型为 int,所以类型错误。

t1 执行赋值成功,add 的两个参数都是 Integer,所以 T 为 Integer 类型。

t2 执行赋值成功,add 的两个参数一个是 Integer,一个是 Float,所以取同一父类的最小级为 Number,故 T 为 Number 类型。

t3 执行赋值成功,add 的两个参数一个是 Integer,一个是 Float,所以取同一父类的最小级为 Object,故 T 为 Object 类型。

t4 执行赋值成功,add 指定了泛型类型为 Integer,所以只能 add 为 Integer 类型或者其子类的参数。

t5 编译直接报错,add 指定了泛型类型为 Integer,所以只能 add 为 Integer 类型或者其子类的参数,不能为 Float。

t6 执行赋值成功,add 指定了泛型类型为 Number,所以只能 add 为 Number 类型或者其子类的参数,Integer 和 Float 均为其子类,所以可以 add 成功。

t0、t1、t2、t3 其实演示了调用泛型方法不指定泛型的几种情况,t4、t5、t6 演示了调用泛型方法指定泛型的情况。 在调用泛型方法的时可以指定泛型,也可以不指定泛型;在不指定泛型时泛型变量的类型为该方法中的几种类型的同一个父类的最小级(直到 Object),在指定泛型时该方法中的几种类型必须是该泛型实例类型或者其子类。切记,java 编译器是通过先检查代码中泛型的类型,然后再进行类型擦除,再进行编译的。

12:问:下面两个方法有什么区别?为什么?

666.png

答:get1 方法直接编译错误,因为编译器在编译前首先进行了泛型检查和泛型擦除才编译,所以等到真正编译时 T 由于没有类型限定自动擦除为 Object 类型,所以只能调用 Object 的方法,而 Object 没有 compareTo 方法。

get2 方法添加了泛型类型限定可以正常使用,因为限定类型为 Comparable 接口,其存在 compareTo 方法,所以 t1、t2 擦除后被强转成功。所以类型限定在泛型类、泛型接口和泛型方法中都可以使用,不过不管该限定是类还是接口都使用 extends 和 & 符号,如果限定类型既有接口也有类则类必须只有一个且放在首位,如果泛型类型变量有多个限定则原始类型就用第一个边界的类型变量来替换。

基础知识:

1: 为什么需要泛型?
1) : 类型安全 (在编译期间判断类型,类型不对则不通过)
2) 设计通用类型 (提高复用率)

2: 用在什么地方

1):  用在类上,叫做泛型类

    public class Animal<T> {

        private T t;

        public T getData() {
            return t;
        }
    }

2):  用在接口上,叫做泛型接口

    public interface FansInterface<K, V> {

        K add(V v);
    }

3):  用在方法上,叫做泛型方法,  (不一定非要在泛型类中,在普通类中也可以申请泛型方法)

    public <V> void test(V v) {
        
    }

3: 泛型注意事项

1): 泛型类型参数不能是基本类型。

  1. : 一旦形参中使用了?通配符,那么除了写入null以外,不可以調用任何和泛型参数有关的方法,当然和泛型参数无关的方法是可以调用的,如:
    public static void test(List<?> list) {
    int size = list.size(); // 正确

    list.add(new Integer(1)); // 错误
    }
    看上面的形参使用了 <?> 通配符, 所以调用size()方法是与泛型无关的,可以调用,但要调用add()方法就会报错,因为<?>表示不确定的类型,一旦加入新类型后,就无法保证类型的安全性,所以list.add()方法是编译失败的。

4: Java泛型无法使用 instanceof关键字,例:

Box<Integer> integerBox = new Box<Integer>();
if (integerBox instanceof Box<Integer>)  // 错误 

因为编译器使用类型擦除, 在运行时不会跟踪类型参数, 所以无法使用instanceof关键字,integerBox 在经过编译器类型擦除后, 会变为 Box integerBox = new Box(); 所以无法使用instanceof关键字

5: 泛型中的继承关系


image.png

可以看出 Integer虽然继承自Number, 但是 Box<Integer>与 Box<Number> 却不是继承关系,

6: 泛型中的通配符

image.png

可以看出,通配符可以分为子类型限定,超类型限定和无限定

子类型的限定, 表示类型的上界,类似泛型的类型变量限定,
格式: ? extends X
作用: 1:用于安全的访问数据,
2: 可以访问X 以及 X的子类型
3: 只能写入null, 其余的类型都无法写入。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,185评论 6 503
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,652评论 3 393
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,524评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,339评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,387评论 6 391
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,287评论 1 301
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,130评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,985评论 0 275
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,420评论 1 313
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,617评论 3 334
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,779评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,477评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,088评论 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,716评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,857评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,876评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,700评论 2 354

推荐阅读更多精彩内容

  • 参考地址:《Java 泛型,你了解类型擦除吗?》 《Java中的逆变与协变》 《java 泛型中 T、E .....
    琦小虾阅读 3,006评论 0 11
  • 泛型,一个孤独的守门者。 大家可能会有疑问,我为什么叫做泛型是一个守门者。这其实是我个人的看法而已,我的意思是说泛...
    程序员BUG阅读 361评论 0 0
  • 泛型 泛型(Generic Type)简介 通常情况的类和函数,我们只需要使用具体的类型即可:要么是基本类型,要么...
    Tenderness4阅读 1,416评论 4 2
  • 参数类型的好处 在 Java 引入泛型之前,泛型程序设计是用继承实现的。ArrayList 类只维护一个 Obje...
    杰哥长得帅阅读 876评论 0 3
  • 百度词条上是这样界定旅行和旅游的概念: “旅行,指远行;去外地办事或游览。去外地行走。不同于旅游。 旅行和旅游的区...
    汉堡是晗宝阅读 1,515评论 8 5