意外的类型int_有关instanceof及泛型类型信息的探究

在课上学习泛型时,老师提到不能使用instanceof这个运算符来检验泛型类型的信息,因为“运行时泛型消失了”:

4a738bc439af3b810ce39b0e34499463.png

我有点不太明白这句话该怎么理解:消失的到底是什么东西?instanceof又是什么?而且后面又一次出现instanceof时我们被告诫尽量避免使用这个运算符,这让我感到很奇怪(注:下图中instanceof后面不应该有括号,它是个运算符而不是方法):

0fe73179e991fc5033c04314e905cf0b.png

一方面我不知道这个东西到底怎么使用,另一方面也不知道为什么要尽量避免使用。此外,在我的想象中泛型<E>中的E在使用时确定了类型以后会被替换掉,如果instanceof检测类型的话应该能检测出来这个确定的类型才对,然而现实中并不能。于是我决定对其进行一番探究,相信如果掌握了它的使用机制,既能在适当的时侯正确使用,又能帮助理解泛型的实现。

最开始我先尝试探究instanceof的作用域。显然,主数据类型是无法进行判断的(将Integer改成int也过不了编译):

98071be482e6149be992bab51ffb19fd.png

但是Java为主数据类型提供了自动封装成对象的机制,所以直接定义成对象就没问题了:

75455541afde8f3c808f46901cc618cf.png

那么如果换成父类呢?众所周知,Object是所有对象的父类。测试结果表明没问题:

e533490bcaab891466f10e75e9e20977.png

为了保险起见以及后续的探究,我补充了两个简单的类以及一个接口,它们之间具有继承关系以及接口的使用:

d7c7c13fc2625145b552dc67d9e8ae9a.png

首先搞了一个子类的对象,分别用本身这个类、父类和接口名进行测试:

3eda8238bdd4ee93a279dab4b93f7e29.png

结果是3个true,这说明无论是父类还是接口,只要继承或引用了,instanceof就都能体现出来。从逻辑上讲,这也是十分合理的:从中文翻译上来讲,instanceof的意思就是“本质上是”,那么继承父类的子类当然也是父类了,接口也是如此。接下来Animal的测试结果也没有什么可说的:

1d6eabe3db9333137fd0955cc0470230.png

接下来一个很有价值的测试点就是多态。对于多态变量,重写和重载方法的选择机制已经比较复杂了,那instanceof会怎样呢?我声明了一个Animal类型的变量并将其实例化为Dog,再次进行了测试:

129bd8d7c1f35beaed5049b94b9a03bb.png

这回的结果仍然是3个true,说明“本质上是”的理解方式仍然行的通。虽然Mark被声明为了Animal,但是其实例化出来的是Dog,因为Dog继承了Animal又引用了Mammal接口,所以当然Mark在本质上也是Animal和Mammal。那么如果把Animal换成接口Mammal呢?

6aa9ff2e901f30b624cc0b3dd24aebf2.png

不出意外地,结果仍然是3个true,因为Mark本质上仍然是Dog,它被声明成啥并不重要。接下来测试测试泛型吧:

4f5d5cf6c59fd1600ac78322067b2b08.png

可以看到a被实例化为了只能装String的HashSet,无论是接口Set还是HashSet都能通过instanceof,因为a在本质上当然是HashSet也是Set。那么对于更为具体的Set<String>以及HashSet<String>呢?

47b3d082f3b791f87e02a4f483c1841e.png

结果是根本不能通过编译。在这里,IDE给出的错误提示告诉我们,一旦泛型被参数化了就不能再执行instanceof了,建议我们将尖括号里面的String改成问号,并解释说在运行时泛型类型信息会被抹掉。我先试了一下改成问号,果然没问题了:

4b6888f0be6c51d6ef9d1e9fe0c5c351.png

所以看样子在运行时并不是将XX<E>中的E替换成某种具体的类型,而是把整个<E>抹掉了只剩下XX,这才能解释为什么我限定了括号里是String时不能通过编译而去掉或者换成通配符才行。这颠覆了我最初的想象!为了确保推理正确,我又去网上查找了资料,https://www.it1352.com/788122.html 这个网站验证了我的探究结果。

总结一下:instanceof的使用方法是看一个对象的“本质”,对主数据类型不适用;“本质”指的是实例化new的类,那个类的本身、其父类、引用的接口都能通过instanceof检测,这与这个对象被声明成什么类无关;泛型在运行时被抹掉的信息是括号中在使用时确定的类,因此当然不能用instanceof检测出具体的类型,这也就解答了文首的第一个问题。回过头来再看那一下不建议使用instanceof的那段话:

6c2c754a0b5acf34d9c8f05ed54c3c5c.png

当然不能用父类中使用instanceof来检测子类了。不过我认为这个说法可能有些过于绝对,以及课程中讲的“不能将父类强转为子类”。回想当初自己写桥牌软件时用socket传输东西,在传送过程中用的都是Object类型,而传的东西原来是什么类型实际上还隐藏在它自身,在接收的时候完全可以强转回它原来的类型,所以应该也能用instanceof检测出来。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值