范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文

互联网大厂面试什么是Java语言中的类型擦除?

  什么是泛型?
  首先来讲泛型操作是从JDK5开始引入Java语言的一个新特性,其允许在定义类或者是接口的时候使用一个类型参数,并且这个类型参数可以在使用的时候被替换成一个具体的参数。使用泛型最大的好处就是可以极大的提升代码的复用性。
  以List为例,我们可以在List集合中放入任何的数据类型例如String、Integer等等,当然也可以放入对象类型。如果不使用泛型那么就会出现想要使用String类型的List集合的时候需要定义一个String类型的List集合,需要使用Integer类型的List的集合的时候就需要定义相应类型的集合,这样做就有点复杂了,为了解决这样的问题,就出现了我们的泛型操作。各种语言对泛型操作的处理机制?
  通常情况下,编译器需要通过如下的几种方式来对泛型数据类型进行处理。在实例化一个泛型类或者是一个泛型类型的方法的时候,对于每一种数据类型都产生一份新的代码来进行具体的支撑,例如针对List的泛型操作,如果使用了String类型,就生成一份String类型的List代码,使用Integer就生成一份Integer的List代码。对于每个使用泛型操作的类或者方法来讲生成的代码都是唯一的一份,并且将所有的类型通过映射都映射到泛型上,在需要具体使用的时候对类型进行判断进行转换,使得泛型能够正常的操作。
  在C++语言中的泛型就是通过第一种方式来实现的,也就是说C++语言的编译器会为每个泛型都生成一份对应的执行代码,在代码中String类型与Integer类型对应的泛型类是不一样的。而这样带来的后果就是在编译后的代码中会存在大量的冗余代码。
  在C#语言中泛型操作无论是在源码中还是在编译后的中间代码中或者是在运行时期的代码中都是存在不同类型的数据代码,唯一不同的是这些代码是在运行期间生成的,并且有自己的虚地址表示,这种方式被称为是类型膨胀。而基于这种方式所实现的泛型操作被称为是真实泛型。
  在Java语言中的泛型与前面两者是不一样的,它只在源代码中存在,在编译之后的字节码中就会被替换成原生类,并且在相应的代码中加入了强制类型转换。所以对于Java语言而言,ArrayList和ArrayList其实就是同一个类型,对于Java来讲泛型操作可以称之为Java语言的优势,而在Java语言中使用到的对泛型的操作则是被称为是类型擦除,而基于这种方法实现的泛型操作被称为是伪泛型。
  C++和C#是使用Code specialization的处理机制,前面提到,他有一个缺点,那就是会导致代码膨胀。另外一个弊端是在引用类型系统中,浪费空间,因为引用类型集合中元素本质上都是一个指针。没必要为每个类型都产生一份执行代码。而这也是Java编译器中采用Code sharing方式处理泛型的主要原因。
  Java编译器通过Code sharing方式为每个泛型类型创建唯一的字节码表示,并且将该泛型类型的实例都映射到这个唯一的字节码表示上。将多种泛型类型实例映射到唯一的字节码表示是通过类型擦除(type erasure)实现的。什么是Java语言的类型擦除?
  什么是类型擦除?类型擦除是指通过类型参数组合的方式,将泛型类型的实例对象关联到同一份字节码文件上。编译器最终只会为泛型类型提供一份统一的字节码,并且将相关的实例对象关联到这一份字节码文件上。
  类型擦除的关键就是在于从泛型类型中清除类型参数的信息,并且在使用的时候需要对传入的真实参数进行类型检查和类型转换。可以简单的理解为将泛型类型的代码转换成了普通类型的代码,只不过对于Java编译器来讲,是将对应的字节码文件进行了转换。
  类型擦除器过程主要分为如下两个步骤将所有的泛型有关的参数用最顶级的父类进行替换移除所有的具体类型相关的参数Java语言泛型处理过程
  首先来看一段简单的代码public static void main(String[] args) {       Map map = new HashMap();       map.put("name", "nihui");       map.put("age", "22");       System.out.println(map.get("name"));       System.out.println(map.get("age"));   }
  经过反编译之后的结果如下public static void main(String[] args) {       Map map = new HashMap();       map.put("name", "nihui");       map.put("age", "22");      System.out.println((String) map.get("name"));       System.out.println((String) map.get("age"));   }
  从反编译的结果来看,我们对于KV键值对的处理都已经不存在了,只留下了我们想要实现的部分的代码,就是直接进行类型的存储。interface Comparable {     public int compareTo(A that); }  public final class NumericValue implements Comparable {     private byte value;      public NumericValue(byte value) {         this.value = value;     }      public byte getValue() {         return value;     }      public int compareTo(NumericValue that) {         return this.value - that.value;     } }
  反编译之后的结果 interface Comparable {   public int compareTo( Object that); }   public final class NumericValue     implements Comparable {     public NumericValue(byte value)     {         this.value = value;     }     public byte getValue()     {         return value;     }     public int compareTo(NumericValue that)     {         return value - that.value;     }     public volatile int compareTo(Object obj)     {         return compareTo((NumericValue)obj);     }     private byte value; }
  编译之前的代码public class Collections {     public static > A max(Collection xs) {         Iterator xi = xs.iterator();         A w = xi.next();         while (xi.hasNext()) {             A x = xi.next();             if (w.compareTo(x) < 0)                 w = x;         }         return w;     } }
  反编译之后的代码public class Collections {     public Collections()     {     }     public static Comparable max(Collection xs)     {         Iterator xi = xs.iterator();         Comparable w = (Comparable)xi.next();         while(xi.hasNext())         {             Comparable x = (Comparable)xi.next();             if(w.compareTo(x) < 0)                 w = x;         }         return w;     } }
  第2个泛型类Comparable 擦除后 A被替换为最左边界Object。Comparable的类型参数NumericValue被擦除掉,但是这直 接导致NumericValue没有实现接口Comparable的compareTo(Object that)方法,
  于是编译器在其中添加了一个桥接方法。 从第3个示例中限定了类型参数的边界>A,A必须为Comparable的子类,按照类型擦除的过程,先讲所有的类型参数 ti换为最左边界Comparable,然后去掉参数类型A,得到最终的擦除后结果。泛型带来的问题有哪些?
  一、泛型方法的重载public class GenericTypes {        public static void method(List list) {           System.out.println("invoke method(List list)");       }        public static void method(List list) {           System.out.println("invoke method(List list)");       }   }
  从上面这段代码中我们可以看到两个方法由于参数类型不同形成了方法的重载,但是这段代码在实际编译的过程中是没法通过的,因为在之前的内容中我们提到过List和List在Java语言来看由于类型擦除会将其认定为同一个类型,这样就会变成两个参数一样并且方法名一样的方法,这个在Java操作中是不被允许的。
  二、遇到Catch
  我们都知道在Java语言中会经常遇到异常捕获,如果我们在开发过程中自定义了一个通用的异常处理,那么就会有各种各样的异常被通用的异常处理捕获,这个时候如果想要实现不同的异常进行不同的处理那就非常难了
  三、当泛型类型包含静态变量public class StaticTest{     public static void main(String[] args){         GT gti = new GT();         gti.var=1;         GT gts = new GT();         gts.var=2;         System.out.println(gti.var);     } } class GT{     public static int var=0;     public void nothing(T x){} }
  如上面代码所示,如果在泛型中遇到的静态变量,会出现什么样的结果呢?我们都知道静态变量是与类的存在是有关的,也就是说对于一个泛型如果与到了一个静态变量,那么这个静态变量就是对于所有的泛型类所共享的。而上面的代码执行结果也就显而易见了。输出的结果应该是2。因为对于第一个操作来讲,将泛型中的静态变量改成了1,但是由于静态变量是共享的,在第二个操作中就会将对应的值改成2,所以最终的输出结果应该是2。总结
  综上所述,在虚拟机中没有泛型的概念,只有普通类与普通方法的概念,所有泛型类型在编译之后都会被进行类型擦除操作,也就是说泛型并没有自己独立存在的对象进行存储,也就不会有反射等一些高级操作。在使用泛型操作的时候一定要提前的去对类型做处理让编译器提前就知道需要处理的类型的是什么。这样可以在提升编译器处理效率的同时也可以避免带来各种各样的问题。

宋奇推荐算法并非一成不变,需重视其创新价值和技术活力中新经纬1月19日电(王玉玲)近日,清华大学社会科学学院积极心理学研究中心在线上举行用户使用算法推荐与信息茧房的关系再思考主题研讨会,发布了研究成果破茧还是筑茧?用户使用算法推荐与Soul发布第四季度生态安全报告对网络诈骗重拳出击作为备受年轻人喜爱的新型开放式社交平台,Soul自成立以来就致力于为用户构筑一个可以真实的表达自我,无压力的沟通交流的社交空间,帮助提升用户的幸福感和归属感。也正因如此,Soul一黑喉潜鸟现身泰山景区泰山野生鸟类记录已达370种记者近日从山东泰山景区管委会获悉,工作人员在泰山冬季野生鸟类调查中发现黑喉潜鸟。目前,泰山野生鸟类记录达20目65科370种。其中,国家一级保护野生动物12种,国家二级保护野生动物陕西壶口瀑布旅游区新春喜迎四方游客图为咆哮奔腾的壶口主瀑布。兰华摄图为景区广场上的舞龙节目表演。兰华摄图为陕北大秧歌在壶口岸边为游客演出。兰华摄图为舞狮表演在壶口岸边吸引了众多游客观赏。兰华摄图为舞龙现场。兰华摄图我们的节日。春节黄河厂社区开展新春送福情暖万家主题活动为深入推动新时代文明实践活动走进千家万户,营造欢乐喜庆的节日氛围,连日来,黄河厂社区开展了新春送福情暖万家送春联主题活动。一副副吉祥如意的春联传递着满满的中国传统文化气息,让居民群白马驿之祸9位皇子被杀,30多位臣子被投进黄河,唐朝自此亡此生谁料,心在天山,身老沧州。当年万里觅封侯这首诗是宋朝著名诗人陆游所写,描述了自己一生有着远大的抱负,志气在那高高的山峰之巅,然而却不料到人生总是有许多的意外,在一个不知名的地方2023年中新天津生态城将塑造京津冀最美亲海岸线北京日报客户端记者白波中新天津生态城1月18日召开2023年工作会议。北京日报客户端记者获悉,2023年,生态城将推动万达文旅岛开工建设,塑造京津冀最美亲海岸线。2022年,中新天守正创新开新局勇毅前行再出发华山镇黄河厂社区2023年新年献词日月开新元,万象启新篇。在这辞旧迎新继往开来的美好时刻,黄河厂社区向长期以来关心支持黄河厂社区发展的各级领导社会各界致以衷心的感谢和美好的祝愿!向奋战在黄河厂社区各条战线的工作人员西藏曲水希望文明生态团结幸福的种子生根发芽中国西藏网讯西藏自治区拉萨市曲水县位于西藏腹地拉萨河下游雅鲁藏布江中游北岸。历史悠久,物产富饶。相传吐蕃时期公主进藏时,途径曲水,便将大唐带来的种子播撒在这里,从此这片土地便孕育出七彩风车迎新春新年出行第一站鲤鱼滩!来源绿色中国梦幻鲤鱼滩七彩风车节浙江常山天马鲤鱼滩风车节新春炫彩开幕虎辞盛岁,兔跃新程去哪里拥抱新年第一缕阳光去哪里见证新年第一抹缤纷去哪里收获新年第一份好运鲤鱼滩新年限定七彩风车四海同心共享中国年国际友人赶百年蒲河大集(国际友人赶百年沈北新区蒲河大集摄影白冰冰)新春到来之际,来自奥地利德国俄罗斯泰国等多位国际友人来到300年历史的沈阳市沈北新区蒲河大集,赶大集备年货,一起迎接中国年。(小朋友吃冰
王者荣耀黄金排位禁的英雄都有哪些?黄金段位排位赛不是征兆模式,因此不能BAN英雄。回答完啦其实小编我一般随到45楼都是队友让我禁啥我就禁啥,大气都不敢出,生怕人家生气挂机(),然后注意下队友常用英雄,尽量别禁这些,英雄联盟虚空是不是最强的势力?lol里面的势力有很多,比如人间的死对头,德玛西亚和诺克萨斯。还有战争学院班德尔城的小矮子们暗影岛的恶徒弗雷尔卓德的冰天雪地艾欧尼亚以及恕瑞玛等,大大小小总共有26个势力生存在瓦罗王者荣耀里大家都说代代版本削宫本,到底削了什么?以前的宫本武藏是怎么样的?首先,宫本武藏是王者荣耀比较早期上线的一名英雄,而且宫本武藏最初登场时是一名刺客,与李白一起成就了当时的刺客荣耀,对王者峡谷形成了绝对的统治。故而,宫本武藏在早期是王者荣耀中比较具你觉得魔兽争霸3的英雄中,哪位英雄是最强的英雄杀手?剑圣进不了前3。魔兽争霸3游戏中英雄杀手排行榜。欢迎补充!top5恶魔猎手dh埃辛诺斯的双刃!单挑情况下不虚任何人,也是法师杀手。敏捷英雄的身材,却有着力量英雄的肉度,可能他杀不死王者荣耀的玩家们,敢不敢晒一下你的本命英雄?万年单排王来咯,跟大家一起晒本命英雄!先来晒三个,看看有没有也是你的本命英雄呢?首先,关羽闪亮登场从最初的绿帽关羽,到现在终于给他穿上了新春的衣服!都说关羽的操作难度在王者英雄当中英雄联盟中小鱼人的强势期是多久?一看见对面小鱼人中单,我反手一个德玛,对线舒服的很,清兵推塔就好了!首先说小鱼人属于刺客,一般情况下,刺客分物理和魔法,小鱼主要是魔法,刺客的输出主要来源技能和平a的高爆发,所以只近年春晚小品歌舞更丰富多彩,为什么反倒感觉不如以前吸引人了?感谢邀请。首先说歌舞,春节中国人的节日,欢声笑语的,热热闹闹的,但总不能标新立异搞一些特殊作品吧?!况且随着网络神曲,流量明星的出现,水平不见得高节目不见得好,明星为了流量为了出名怎样改掉驼背的坏习惯?说到驼背,与其密切相关的就是头前引和圆肩,三者同属于上交叉综合症,我们今天就一起讲一下。表现先来看一下头前引,其实很多明星都有这种体态问题,请看左边Taylor的姿态。再看一下圆肩哈尔滨私立高中哪个好一些,收费标准是多少?私立高中目前最好的是德强,其次是工附松雷,学费每年21000加上饭费是30000,加住校加校车大概35000。能去市重点以上的不要考虑私立高中。每个月大小晚课1000,假期补课每天孕妇一定不能用药吗?怀孕期间是不是绝对不能用药呢?现在社会的理念就是怀孕了不能用药,会导致胎儿的发育不良甚至出现胎儿的畸形。确实在上个世纪60年代,反应停的广泛应用导致很多畸形儿的出生,也有其他药物引打算换一个能用3,4年的手机,应该换4g的还是5g的?谢谢邀请。现在智能手机基本普及,大多数人使用的仍是4G智能手机。第一,现在智能手机无论在性能上,价格上都已经适合大多数人的需求。一般千元左右的智能手机基本能满足大多数人的使用需求。