一文讲解Java泛型的本质(非类型擦除),java中高级面试题大全

本文通过一个代码示例探讨了Java中泛型的类型擦除特性,以及在泛型方法中使用数组转换时出现的运行时异常。解释了为何方法一正常而方法二报错,原因是Java运行时没有泛型信息,导致强转失败。同时,文章通过反编译代码揭示了编译器如何处理泛型信息。最后,作者分享了对于程序员在当前就业环境下的思考和建议。
摘要由CSDN通过智能技术生成

==

昨天,在逛论坛时遇到个这么个问题,上代码:

public class GenericTest {

//方法一

public static <T extends Comparable> List sort(List list) {

return Arrays.asList(list.toArray((T[]) new Comparable[list.size()]));

}

//方法二

public static <T extends Comparable> T[] sort2(List list) {

// 这里没报错

return list.toArray((T[]) new Comparable[list.size()]);

}

public static void main(String[] args) {

List list = new ArrayList<>();

list.add(1);

list.add(2);

// 方法一调用正常

System.out.println(sort(list).getClass());

// 方法二调用报错了,这里报错了

System.out.println(sort2(list).getClass());

}

}

这个问题有以下四个现象:

  • 方法一调用完全正常;

  • 方法二调用报错了;

  • 《一线大厂Java面试题解析+后端开发学习笔记+最新架构讲解视频+实战项目源码讲义》开源 方法二报错的地方是在System.out.println(sort2(list).getClass());这行,而不是return list.toArray((T[]) new Comparable[list.size()]);这行;

  • 报的错是[Ljava.lang.Comparable; cannot be cast to [Ljava.lang.Integer;

怎么样?你心中有答案嘛?类型擦除?怎么擦?摩擦摩擦?

解决

==

刚拿到这道题,我也是一脸懵逼,这要报错也应该是在return list.toArray((T[]) new Comparable[list.size()]);这行啊,而且要报错应该两个方法都报错啊。

抱着不放弃不抛弃的心态,彤哥做了大量的实验,终于得出了泛型的本质,且听我娓娓道来。

小插曲


首先,我们要明白,java中的数组是不支持向下转型的,但是如果本身就是那个类型的是可以转过去的,请看下面的例子:

public static void main(String[] args) {

Object[] objs = new Object[]{1};

// 类型转换错误

// Integer[] ins = (Integer[]) objs;

Object[] objs2 = new Integer[]{1};

// 不报错

Integer[] ins2 = (Integer[]) objs2;

}

类型擦除


java里的泛型是假泛型,只在编译期有效,在运行时是没有泛型的概念的,举个简单的例子:

public static void main(String[] args) {

List strList = Arrays.asList(“1”);

List intList = Arrays.asList(1);

// 打印:true

System.out.println(strList.getClass() == intList.getClass());

}

可以看到两个list的类型是一样的,如果你觉得这个例子不够 Java开源项目【ali1024.coding.net/public/P7/Java/git】 说服力,那我给你个过分点的例子:

public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {

List strList = new ArrayList<>();

Method addMethod = strList.getClass().getMethod(“add”, Object.class);

addMethod.invoke(strList, 1);

addMethod.invoke(strList, true);

addMethod.invoke(strList, new Long(1));

addMethod.invoke(strList, new Byte[]{1});

// 打印:[1, true, 1, 1]

System.out.println(strList);

}

瞧,我可以往一个String类型的List中扔任何我想扔的东西,服不服?!

所以说java里面的泛型是假的,运行时不存在滴。

回归正题


数组不能向下强转我懂了,类型擦除我也懂了,似乎还是过不好这一生,呃不是,是还是解决不了这道题啊?

呃,好像是~~

我们再来看一个简单的例子:

// GenericTest2.java(源码)

public class GenericTest2 {

public static void main(String[] args) {

System.out.println(raw(“1”));

}

public static T raw(T t) {

return t;

}

}

// GenericTest2.class(反编译)

public class GenericTest2 {

public GenericTest2() {

}

public static void main(String[] args) {

System.out.println((String)raw(“1”));

}

public static T raw(T t) {

return t;

}

}

嗯~似乎看出来点端倪,反编译后多了个构造方法。

呃,没错。还有呢?

仔细一看,System.out.println((String)raw("1"));这一句多加了个String强转。

这就是关键所在,结合类型擦除,运行时并没有所谓的泛型,所以raw()返回的其实是Object,但是调用者自己知道我要的是String类型啊,所以我就知道强转一下喽。

我们再来看个极端的例子:

// GenericTest2.java(源码)

public class GenericTest2 {

public static void main(String[] args) {

System.out.println(raw(“1”));

}

写在最后

作为一名即将求职的程序员,面对一个可能跟近些年非常不同的 2019 年,你的就业机会和风口会出现在哪里?在这种新环境下,工作应该选择大厂还是小公司?已有几年工作经验的老兵,又应该如何保持和提升自身竞争力,转被动为主动?

就目前大环境来看,跳槽成功的难度比往年高很多。一个明显的感受:今年的面试,无论一面还是二面,都很考验Java程序员的技术功底。

最近我整理了一份复习用的面试题及面试高频的考点题及技术点梳理成一份“Java经典面试问题(含答案解析).pdf和一份网上搜集的“Java程序员面试笔试真题库.pdf”(实际上比预期多花了不少精力),包含分布式架构、高可扩展、高性能、高并发、Jvm性能调优、Spring,MyBatis,Nginx源码分析,Redis,ActiveMQ、Mycat、Netty、Kafka、Mysql、Zookeeper、Tomcat、Docker、Dubbo、Nginx等多个知识点高级进阶干货!

由于篇幅有限,为了方便大家观看,这里以图片的形式给大家展示部分的目录和答案截图!

Java经典面试问题(含答案解析)

阿里巴巴技术笔试心得

tis,Nginx源码分析,Redis,ActiveMQ、Mycat、Netty、Kafka、Mysql、Zookeeper、Tomcat、Docker、Dubbo、Nginx等多个知识点高级进阶干货!**

由于篇幅有限,为了方便大家观看,这里以图片的形式给大家展示部分的目录和答案截图!
[外链图片转存中…(img-FzRXS8rM-1650621510850)]

Java经典面试问题(含答案解析)

[外链图片转存中…(img-uOZD80vE-1650621510851)]

阿里巴巴技术笔试心得

[外链图片转存中…(img-4iijmIF1-1650621510852)]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值