擦除

Java泛型编程如何避免类型擦除问题 类型擦除是指在编译时,泛型类型信息被擦除,替换为它们的原始类型(如Object)。理解类型擦除的原理和影响,以及掌握如何在编程中处理这些问题,将有助于我们更好地利用Java泛型编程的优势,提高代码的质量和可维护性。因此,在运行时,泛型类型信息不再存在,导致无法直接访问这些类型。例如,我们可以为泛型类添加一个Class类型的类型参数,以便在运行时访问泛型类型。通过利用这些特性,我们可以减少显式类型参数的使用,从而减轻类型擦除带来的负担。通过这种方式,我们可以在运行时访问泛型类型,从而避免一些类型擦除问题。 阅读详情

Java泛型-类型擦除

一、概述

      Java泛型在使用过程有诸多的问题,如不存在List<String>.class, List<Integer>不能赋值给List<Number>(不可协变),奇怪的ClassCastException等。 正确的使用Java泛型需要深入的了解Java的一些概念,如协变,桥接方法,以及这篇笔记记录的类型擦除。Java泛型的处理几乎都在编译器中进行,编译器生成的bytecode是不包涵泛型信息的,泛型类型信息将在编译处理是被擦除,这个过程即类型擦除。

二、编译器如何处理泛型?

     通常情况下,一个编译器处理泛型有两种方式:
     1.Code specialization。在实例化一个泛型类或泛型方法时都产生一份新的目标代码(字节码or二进制代码)。例如,针对一个泛型list,可能需要 针对string,integer,float产生三份目标代码。
     2.Code sharing。对每个泛型类只生成唯一的一份目标代码;该泛型类的所有实例都映射到这份目标代码上,在需要的时候执行类型检查和类型转换。
     C++中的模板(template)是典型的Code specialization实现。C++编译器会为每一个泛型类实例生成一份执行代码。执行代码中integer list和string list是两种不同的类型。这样会导致代码膨胀(code bloat),不过有经验的C++程序员可以有技巧的避免代码膨胀。
     Code specialization另外一个弊端是在引用类型系统中,浪费空间,因为引用类型集合中元素本质上都是一个指针。没必要为每个类型都产生一份执行代码。而这也是Java编译器中采用Code sharing方式处理泛型的主要原因。
     Java编译器通过Code sharing方式为每个泛型类型创建唯一的字节码表示,并且将该泛型类型的实例都映射到这个唯一的字节码表示上。将多种泛型类形实例映射到唯一的字节码表示是通过类型擦除(type erasue)实现的。

三、 什么是类型擦除?

     类型擦除指的是通过类型参数合并,将泛型类型实例关联到同一份字节码上。编译器只为泛型类型生成一份字节码,并将其实例关联到这份字节码上。类型擦除的关键在于从泛型类型中清除类型参数的相关信息,并且再必要的时候添加类型检查和类型转换的方法。
     类型擦除可以简单的理解为将泛型java代码转换为普通java代码,只不过编译器更直接点,将泛型java代码直接转换成普通java字节码。
     类型擦除的主要过程如下:
     1.将所有的泛型参数用其最左边界(最顶级的父类型)类型替换。
     2.移除所有的类型参数。
     如
interface Comparable <A> { 
  public int compareTo( A that); 
} 
final class NumericValue implements Comparable <NumericValue> { 
  priva te byte value;  
  public  NumericValue (byte value) { this.value = value; }  
  public  byte getValue() { return value; }  
  public  int compareTo( NumericValue t hat) { return this.value - that.value; } 
} 
-----------------
class Collections {  
  public static <A extends Comparable<A>>A max(Collection <A> xs) { 
    Iterator <A> xi = xs.iterator(); 
    A w = xi.next(); 
    while (xi.hasNext()) { 
      A x = xi.next(); 
      if (w.compareTo(x) < 0) w = x; 
    } 
    return w; 
  } 
} 
final class Test { 
  public static void main (String[ ] args) { 
    LinkedList <NumericValue> numberList = new LinkedList <NumericValue> (); 
    numberList .add(new NumericValue((byte)0));  
    numberList .add(new NumericValue((byte)1));  
    NumericValue y = Collections.max( numberList );  
  } 
}
经过类型擦除后的类型为
 interface Comparable { 
  public int compareTo( Object that); 
} 
final class NumericValue implements Comparable { 
  priva te byte value;  
  public  NumericValue (byte value) { this.value = value; }  
  public  byte getValue() { return value; }  
  public  int compareTo( NumericValue t hat)   { return this.value - that.value; } 
  public  int compareTo(Object that) { return this.compareTo((NumericValue)that);  } 
} 
-------------
class 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; 
  } 
} 
final class Test { 
  public static void main (String[ ] args) { 
    LinkedList numberList = new LinkedList(); 
    numberList .add(new NumericValue((byte)0));  ,
    numberList .add(new NumericValue((byte)1));  
    NumericValue y = (NumericValue) Collections.max( numberList );  
  } 
}
第一个泛型类Comparable <A>擦除后 A被替换为最左边界Object。Comparable<NumericValue>的类型参数NumericValue被擦除掉,但是这直 接导致NumericValue没有实现接口Comparable的compareTo(Object that)方法,于是编译器充当好人,添加了一个桥接方法。
第二个示例中限定了类型参数的边界<A extends Comparable<A>>A,A必须为Comparable<A>的子类,按照类型擦除的过程,先讲所有的类型参数 ti换为最左边界Comparable<A>,然后去掉参数类型A,得到最终的擦除后结果。

四、类型擦除带来的问题

     正是由于类型擦除的隐蔽存在,直接导致了众多的泛型灵异问题。
 Q1.用同一泛型类的实例区分方法签名?——NO!
    import java.util.*;

    public class Erasure{

            public void test(List<String> ls){
                System.out.println("Sting");
            }
            public void test(List<Integer> li){
                System.out.println("Integer");
            }
    }
编译该类,

 

参数类型明明不一样啊,一个List<String>,一个是List<Integer>,但是,偷偷的说,type erasure之后,它就都是List了⋯⋯
Q2. 同时catch同一个泛型异常类的多个实例?——NO!
同理,如果定义了一个泛型一场类GenericException<T>,千万别同时catch GenericException<Integer> 和GenericException<String>,因为他们是一样一样滴⋯⋯
Q3.泛型类的静态变量是共享的?——Yes!
猜猜这段代码的输出是什么?
import java.util.*;

public class StaticTest{
    public static void main(String[] args){
        GT<Integer> gti = new GT<Integer>();
        gti.var=1;
        GT<String> gts = new GT<String>();
        gts.var=2;
        System.out.println(gti.var);
    }
}
class GT<T>{
    public static int var=0;
    public void nothing(T x){}
}
答案是——2!由于经过类型擦除,所有的泛型类实例都关联到同一份字节码上,泛型类的所有静态变量是共享的。

五、Just remember

1.虚拟机中没有泛型,只有普通类和普通方法
2.所有泛型类的类型参数在编译时都会被擦除
3.创建泛型对象时请指明类型,让编译器尽早的做参数检查(Effective Java,第23条:请不要在新代码中使用原生态类型)
4.不要忽略编译器的警告信息,那意味着潜在的ClassCastException等着你。

.NET 笔迹擦除8边形 【声明】优快云只做转发不做时时更新,最新博客请关注博客园笔迹擦除是白板软件的核心功能,擦除是以固定形状对笔迹进行碰撞测试,如有相关则分割Stroke线条。 阅读详情

相关推荐

Java 泛型擦除后的三种补救方法

Java中的泛型,在运行时刻其具体类型是被擦除的,这样我们就不能用new T(),instanceof等关操作,特别是对泛型类型的类的实例化问题,在此根据《Thinking in Java》中所讲的对类型擦除所带来问题的三种解决方案,比较了其各自的优缺点。

Java 类型擦除

Java泛型-类型擦除 一、概述 Java泛型在使用过程有诸多的问题,如不存在List.class, List不能赋值给List(不可协变),奇怪的ClassCastException等。 正确的使用Java泛型需要深入的了解Java的一些概念,如协变,桥接方法,以及这篇笔记记录的类型擦除。Java泛型的处理几乎都在编译器中进行,编译器生成的bytecode是不包涵泛型信息的,...

xiangjingjing 360

EEGLAB安装、EDF数据导入、EEG预处理(Matlab)

目录下载和安装下载安装遇到问题及解决方案导入EDF数据EEG预处理 下载和安装 下载 链接:https://pan.baidu.com/s/17eMT6B7LgZ4PyqWvD5ixmg 提取码:12gz 安装 **第一步:**将下载下来的文件解压,修改名称为eeglab,将此文件夹存放在matlab的安装目录里的toolbox文件夹下,下图是我的路径,需要拷贝到自己相对应的路径中 第二步: 打开Matlab软件,点击主页中的设置路径 设置路径 点击添加并包含子文件夹,将eeglab文件夹添加进来,保

y18771025420的博客 1万+

泛型之类型擦除

泛型之类型擦除         泛型信息只存在于代码编译阶段,在进入JVM之前,与泛型相关的信息会被擦除掉,专业术语叫做类型擦除。        通俗地讲,泛型类和普通类在java虚拟机内没有什么不同。 实例: List&lt;String&gt; 1=new ArrayList&lt;String&gt;(); List&lt;Integer&gt; 2=new ArrayList&l...

weixin_42560233的博客 220

高分思路!挑战7天完成一篇网状meta DAY1-7

PASSION!继续析挑战,7天完成一篇网状meta分!

MR_SCI_help的博客 786

鸿蒙【ArkTS】使用TS装饰器封装网络请求HTTP

在HarmonyOS应用开发中,通过HTTP访问网络,可以使用官方提供的@ohos.net.http模块。但是官方提供的直接使用不太好使用,需要封装下才好。这里采用TS的装饰器实现AOP效果 完成前后端接口风格的统一

weixin_60376559的博客 5611

Java 泛型:深入理解泛型的类型擦除

泛型代码和虚拟机 Java 中的的泛型是伪泛型,为什这么说呢?因为 Java 在编译期间,所有的泛型信息都被擦除掉。称为类型擦除(type erasure) 在 Java 虚拟机中没有泛型类型对象 – 所有对象都是属于普通类 , 所以我们要了解一下 类型擦除 的概念。 1. 类型擦除 无论何时定义一个泛型类型,都会自动提供一个响应的 原始类型 (raw type)(不存在泛型 )。原始类型的名字...

Strange_Monkey的博客 3165

单细胞转录组分析(scRNA-seq)

单细胞转录组测序(Single-cell RNA sequencing,scRNA-seq)是一种高通量测序技术,可以在单细胞水平解析基因表达情况,揭示细胞异质性,探索稀有细胞类型,并研究细胞状态转换及动态调控机制。与传统的。

大甘的博客 6149

Java泛型-类型擦除

一、概述   Java泛型在使用过程有诸多的问题,如不存在List.class, List不能赋值给List(不可协变),奇怪的ClassCastException等。 正确的使用Java泛型需要深入的了解Java的一些概念,如协变,桥接方法,以及这篇笔记记录的类型擦除。Java泛型的处理几乎都在编译器中进行,编译器生成的bytecode是不包涵泛型信息的,泛型类型信息将在编译处理是被

清水寺小和尚的博客 1026

详解舵机的基本原理以及控制方法

文章目录什么是舵机?伺服控制硬件连接舵机规格SG90MG90SMG996R总结 什么是舵机? 舵机是伺服电机的一种,伺服电机就是带有反馈环节的电机,我们可以通过伺服电机进行精确的位置控制或者输出较高的扭矩; 舵机也叫也叫 RC 伺服器,通常用于机器人项目,也可以在遥控汽车,飞机等航模中找到它们。 类似舵机这样的伺服系统通常由小型电动机,电位计,嵌入式控制系统和变速箱组成。 电机输出轴的位置由内部电位计不断采样测量,并与微控制器(例如STM32,Arduino)设置的目标位置进行比较; 根据相应的偏差,控制

一名热爱技术的工程师的博客。分享技术干货,记录美好生活。永远相信美好的事情即将发生。 4万+

华为OD机试真题-查找单入口空闲区域(Py/Java/C/C++/Js/Go)

华为OD机试(机考)双机位C卷 【查找单入口空闲区域】,提供Java、C++、Python、Go、JavaScript源码实现,并提供完整思路讲解,以及在线OJ模拟做题。华为OD机试 - 查找单入口空闲区域。

qq_45776114的博客 1268

基于STM32的Flash擦除方式

本文主要介绍STM32的内部Flash擦除方式和擦除长文件的功能函数怎样编写。并且介绍一些注意事项,如只想擦除当前地址,却发现上下地址都出现了擦除等问题。阅读完本文可以使你能够正常的完成Flash擦除。并对擦除时会影响的地址大小有一个深入的认识,并在对页擦除时,页的起始地址和大小有所了解。...

2万+

【K210+STM32项目】基于K210与STM32协同工作的智能垃圾分类系统设计与实现(更新3.0版本)(完整工程资料源码)

STM32F407STM32F407_2(含有app功能)

嵌入式技术开发 2492

【Java】 泛型擦除

1. 泛型擦除的介绍 1.1 泛型擦除的原因 1.2 泛型擦除规则 1.3 泛型擦除规则的验证 2. 通过反射获取被擦除的泛型信息 3. 使用匿名内部类解决泛型擦除导致的问题 4. 泛型擦除在Flink中的坑 4.1 算子实参有时用Lambda表达式代替匿名内部类会报错 4.2 new OutputTag(){}

渐渐的忘记,赶不上明天(读研ing,2024年毕业) 1万+

EtherCAT从站EEPROM组成信息详解(2):字8-15产品标识区

以实际的从站EEPROM数据为例,参照EtherCAT的SII规范,详细分析了从站EEPROM字8-字15的产品标识区内容组成。

kevin1499的博客 719

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

关于flash擦除方式

不同类型的Flash存储器支持的擦除方式可能会有所不同。例如,NAND Flash通常不支持字节级别的擦除,而NOR Flash则可以。擦除操作的具体实现也会受到Flash控制器和存储器本身的设计影响。在进行擦除操作时,还需要注意Flash存储器的耐久性,因为每个存储单元都有有限的擦写次数。这些差异使得NAND Flash和NOR Flash适用于不同的应用场景。NAND Flash适合大容量存储,而NOR Flash适合代码存储和执行。二、NAND Flash和NOR Flash在擦除操作上的区别。

读书 行路 做人 成事 4152

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

SFUD擦除策略:页擦除、块擦除与整片擦除的应用场景

SFUD(Serial Flash Universal Driver)是一款使用JEDEC SFDP标准的串行SPI Flash通用驱动库,为开发者提供了高效、灵活的Flash操作接口。在嵌入式系统开发中,Flash擦除操作是数据管理的核心环节,本文将详细解析SFUD支持的三种擦除策略——页擦除、块擦除与整片擦除的技术特性及应用场景,帮助开发者根据实际需求选择最优方案。 ## 📌 认识Flas

gitblog_00025的博客 685

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

esptool芯片擦除功能:全擦除与区域擦除的使用场景

在嵌入式开发中,SPI Flash(串行外设接口闪存)的擦除操作是固件更新和系统维护的关键步骤。然而,开发者常常面临两难选择:全芯片擦除(`erase_flash`)耗时过长影响开发效率,而区域擦除(`erase_region`)若操作不当则可能残留旧数据导致系统异常。本文将深入解析esptool工具中两种擦除功能的实现原理、性能差异与适用场景,帮助开发者在不同开发阶段和生产环境中做出最优选择。 ...

gitblog_00922的博客 1491

用keil怎么擦除_STM32 FLASH擦除、写入以及防止误擦除程序代码

编译环境:(Keil)MDK4.72.10stm32库版本:STM32F10x_StdPeriph_Driver_3.5.0一、本文不对FLASH的基础知识做详细的介绍,不懂得地方请查阅有关资料。对STM32内部FLASH进行编程操作,需要遵循以下流程:1、FLASH解锁;2、清除相关标志位;3、擦除FLASH(先擦除后写入的原因是为了工业上制作方便,即物理实现方便);4、写入FLASH;5、锁定...

weixin_29959615的博客 7151

Java类型擦除

类型擦除 Java中的泛型基本上都是在编译器这个层次来实现的 Java在编译后的字节码(.class)文件中是不包含泛型中的类型信息的,使用泛型的时候加上的类型参数,会被编译器在编译的时候去掉,这个过程就称为类型擦除。如在代码中定义的List<Object>和List<String>等类型,在编译之后都会变成List,JVM看到的只是List,而由泛型附加的类型信息对JVM...

只会写代码 4567

killdisk如何使用_KillDisk –在Windows上安全完整地擦除和擦除磁盘

killdisk如何使用KillDisk is a software used to erase and wipe disk securely and completely on operating systems like Windows, MacOSX, Linux. KillDisk can be used from inside the operating system or by boo...

cunjiu9486的博客 5762

Java泛型类型擦除以及类型擦除带来的问题

我们都知道Java的泛型是伪泛型,即编译期间所有的泛型信息都会被擦除,如我们代码定义了:List<Object>和List<String>,但是对于JVM而言,看到的只有List,由泛型附加的类型信息对于JVM而言是看不到的。原始类型就是擦除去了泛型信息,最后在字节码中的类型变量的真正类型,无论何时定义一个泛型,相应的原始类型都会被自动提供,类型变量擦除,并使用其限定类型(无限定的变量用Object)替换。举例说明其对应的原始类型就是此时原始类型就是Comparable,而不再是Object。

m0_71260900的博客 1432

用keil怎么擦除_分享STM32 FLASH 擦除(以及防止误擦除程序代码)、写入

编译环境:我用的是(Keil)MDK4.7.2stm32库版本:我用的是3.5.0一、本文不对FLASH的基础知识做详细的介绍,不懂得地方请查阅有关资料。对STM32 内部FLASH进行编程操作,需要遵循以下流程:FLASH解锁清除相关标志位擦除FLASH(先擦除后写入的原因是为了工业上制作方便,即物理实现方便)写入FLASH锁定FLASH实例:#define FLASH_PAGE_SIZE (...

weixin_39866966的博客 2563

泛型擦除

1.Java泛型的实现方法:类型擦除 大家都知道,Java的泛型是伪泛型,这是因为Java在编译期间,所有的泛型信息都会被擦掉,正确理解泛型概念的首要前提是理解类型擦除。Java的泛型基本上都是在编译器这个层次上实现的,在生成的字节码中是不包含泛型中的类型信息的,使用泛型的时候加上类型参数,在编译器编译的时候会去掉,这个过程成为类型擦除。 如在代码中定义List和List等类型,在编译后都会变成List,JVM看到的只是List,而由泛型附加的类型信息对JVM是看不到的。Java编译器会在编译时尽可能的发现

qq_43171656的博客 3699

SD 逻辑擦除和物理擦除

SD卡的逻辑擦除和物理擦除是两个不同层面的操作。逻辑擦除由主机通过标准命令(如CMD38)发起,仅标记逻辑地址数据为无效,不立即擦除物理块;物理擦除则由控制器执行,真正清除NAND Flash中的数据,每次都会消耗擦除寿命。主机只能控制逻辑擦除,而物理擦除由控制器在垃圾回收或磨损均衡时自动触发。实际应用中,文件删除通常只触发逻辑擦除,物理擦除会延迟执行。量产测试时,低级格式化才会强制物理擦除。两种擦除方式在操作单位、执行时机和控制权限上都有本质区别。

世事易变,匪石弗转。 563
上一篇: 15.7 擦除的神秘之处
下一篇: 5.8.1 创建类型实例
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值