C# 之 int 挑战 Java 之 Integer

Integer 与 int 的简单理解(Integer.valueOf()源码解析) IntegerCache类,其作用是缓存一部分int类型的自动装箱的对象值,默认情况下是缓存-128到127之间256个数字,即在jvm中无论调用多少次Integer.valueOf(1),最后只会在jvm中存在一个对象。2、如果数据在[-128,127]这个范围内,int和Integer可以完成自动的拆装箱,最终得到的结果是一致的,那如果不在这个范围内是否相等呢,以下通过Integer的源码进行分析。搞通了这个之后,我们来看看Integer.valueOf(100),都做了哪些事。... 阅读详情

《.NET 4.0面向对象编程漫谈》扩充阅读之

 

C#之int挑战Java之Integer

 

注:

    此文是我为本人拙著《.NET 4.0面向对象编程漫谈》所新写的扩充阅读材料。

    本文涉及到一些JVM原理和Java的字节码指令,推荐感兴趣的读者阅读一本有关JVM的经典书籍《深入Java虚拟机(第2版)》,将它与我在《.NET 4.0面向对象编程漫谈》中介绍的CLR原理与IL汇编指令作个对比,相信读者会有一定的启发。而仔细对比两个类似事物的异同,是很有效的学习方法之一。

    今后我还将在个人博客上放出其他的文章,希望能帮助书的读者开拓视野,启发思考,大家一起探讨技术的奥秘。

    本文所述之内容仅代表个人之理解,任何疏漏及错误请直接回贴指出。

 

===============================================================================

 

1 奇特的程序输出

         前段时间,一个学生给我看了一段“非常诡异”的Java代码:

 

public class TestInteger {

    public static void main(String[] args){

        Integer v1=100;

        Integer v2=100;

          System.out.println(v1==v2);  //输出:true

        Integer w1=200;

        Integer w2=200;

          System.out.println(w1==w2);  //输出:false

    }

}

 

         让这个学生最困惑的是,为什么这些如此相似的代码会有这样令人意外的输出?

 

         我平时多使用C#,Java用得不多,初看到这段代码的输出,我也同样非常奇怪:怎么会这样呢?100和200这两个整型数值对Integer这个类有本质上的差别吗?

 

         为了弄明白出现上述现象的底层原因,我使用javap工具反汇编了Java编译器生成的.class文件:

 

 

      

    通过仔细阅读Java编译器生的字节码,我发现以下给Integer变量赋值的语句:

 

         Integer v1=100;

 

         实际上调用的是Integer.valueOf方法。

 

         而完成两个Integer变量比较的以下语句:

 

         System.Console.WriteLine(v1 == v2);

 

         实际生成的是if_acmpne指令。其中的a代表“address”,cmp代表“Compare”,ne代表“not equal”。

 

         这条指令的含义是:比较Java方法栈中的两个操作数(即v1与v2),看看它们是不是指向堆中的同一个对象。

 

         当给v1和v2赋值100时,它们将引用同一个Integer对象。

 

 

         那为什么当值改为200时,v1和v2就“翻脸了”,分别引用不同的Integer对象?

 

         秘密就在于Integer.valueOf方法。幸运的是,Java的类库是开源的,所以我们可以毫不费力地看到相关的源代码:

 

public static Integer valueOf(int i) {

        if(i >= -128 && i <= IntegerCache.high)

            return IntegerCache.cache[i + 128];

        else

            return new Integer(i);

    }

 

         一切真相大白,原来Integer在内部使用了一个私有的静态类IntegerCache,此类内部封装了一个Integer对象的cache数组来缓存Integer对象,其代码如下:

 

         private static class IntegerCache {

                static final Integer cache[];

                //……

         }

 

         再仔细看看IntegerCache内部的代码,会看到它使用静态初始化块在cache数组中保存了[-128,127]区间内的一共256个Integer对象。

 

         当给Integer变量直接赋整数值时,如果这个数值位于[-128,127]内,JVM(Java Virtual Machine)就直接使用cache中缓存的Integer对象,否则,JVM会重新创建一个Integer对象。

 

         一切真相大白。

 

2 进一步探索Integer

 

    我们再进一步地看看这个有趣的Integer:

 

         Integer v1=500;

         Integer v2=300;

         Integer addResult=v1+v2;  //结果:800

         double divResult=(double)v1/v2;      //结果:1.6666666666666667

 

         哟,居然Integer对象支持加减乘除运算耶!它是怎么做到的?

         再次使用javap反汇编.class文件,不难发现:

         Integer类的内部有一个私有int类型的字段value,它代表了Integer对象所“封装”的整数值。

 

         private final int value;

 

         当需要执行v1+v2时,JVM会调用v1和v2两个Integer对象的intValue方法取出其内部所封装的整数值value,然后调用JVM直接支持的iadd指令将这两个整数直接相加,结果送回方法栈中,然后调用Integer.valueOf方法转换为Integer对象,让addResult变量引用这一对象。

         除法则复杂一点,JVM先调用i2d指令将int转换为double,然后再调用ddiv指令完成浮点数相除的工作。

         通过上述分析,我们可以知道,其实Integer类本身并不支持加减乘除,而是由Java编译器将这些加减乘除的语句转换为JVM可以直接执行的字节码指令(比如本例中用到的iadd和ddiv),其中会添加许多条用于类型转换的语句。

         由此可见,与原始数据类型int相比,使用Integer对象直接进行加减乘除会带来较低的运行性能,应避免使用。

 

3 JDK中Integer类的“弯弯绕”设计方案

 

         现在,我们站在一个更高的角度,探讨一下Integer的设计。

         我个人认为,给Integer类型添加一个“对象缓冲”不是一个好的设计,从最前面的示例代码大家一定会感到这一设计给应用层的代码带来了一定的混乱。另外,我们看到JDK设计者只缓存了[-128,127]共256个Integer对象,他可能认为这个区间内的整数是最常用的,所以应该缓存以提升性能。就我来看,这未免有点过于“自以为是”了,说这个区间内的Integer对象用得最多有什么依据?对于那些经常处理>128的整数值的应用程序而言,这个缓存一点用处也没有,是个累赘。就算真要缓存,那也最好由应用程序开发者自己来实现,因为他可以依据自己开发的实际情况缓存真正用到的对象,而不需背着这个包容着256个Integer对象的大包袱。

         而且前面也看到了,基于Integer对象的加减乘除会增加许多不必要的类型转换指令,远不如直接使用原始数据类型更快捷更可靠。

         其实上用得最多的不是Integer对象而是它所封装的一堆静态方法(这些方法提供了诸如类型转换等常用功能),我很怀疑在实际开发中有多少场合需要去创建大量的Integer对象,而且还假设它们封装的数值还位于[-128,127]区间之内?

       缓存Integer对象还对多线程应用程序带来了一定的风险,因为可能会有多个线程同时存取同一个缓存了的Integer对象。不过JDK设计者已经考虑到了这个问题,我看到Integer类的字段都是final的,不可改,是一个不可变类,所以可以在多线程环境下安全地访问。尽管在使用上没问题,但这一切是不是有点弯弯绕?去掉这个对象缓存,Integer类型是不是“更轻爽”“更好用”?

 

4  C# int挑战Java Integer

 

         将Java的设计与.NET(以C#为例)的设计作个比较是有趣的。

         Java将数据类型分为“原始数据类型”和“引用数据类型”两大类,int是原始数据类型,为了向开发者提供一些常用的功能(比如将String转换为int),所以JDK提供了一个引用类型Integer,封装这些功能。

         .NET则不一样,它的数据类型分为“值类型”和“引用数据类型”两大类,int属于值类型,本身就拥有丰富的方法,请看以下C#代码:

 

                   int i = 100;

                   string str = i.ToString();  //int变量本身就拥有“一堆”的方法

 

         使用.NET的反汇编器ildasm查看一下上述代码生成的IL指令,不难发现C#编译器会将int类型映射为System.Int32结构:

 

 

 

 

         注意System.Int32是一个值类型,生成于线程堆栈中,一般来说,在多线程环境下,使用值类型的变量往往比引用类型的变量更安全,因为它减少了多线程访问同一对象所带来的问题。

 

===============================

         简要解释一下:请对比以下两个方法:

 

         void DoSomethingWithValueType(int value);

         void DoSomethingWithReferenceType(MyClass obj);

 

         当多个线程同时执行上述两个方法时,线程函数使用值类型的参数value是比较安全的,不用担心多个线程互相影响,但引用类型的obj参数就要小心了,如果多个线程接收到的obj参数有可能引用同一个MyClass对象,为保证运行结果的正确,有可能需要给此对象加锁。

=================================

        

         与JVM一样,.NET的CLR也提供了add等专用指令完成加减乘除功能。

         从开发者使用角度而言,C#的int既具有与Java的原始数据类型int一样的在虚拟机级别的专用指令,又具有Java包装类Integer所拥有的一些功能,还同时避免了Java中Integer的那种比较古怪的特性,个人认为,C#中的int比Java中的int/Integer更好用,更易用。

         但从探索技术内幕而言则大不一样,Java使用Integer一个类就“搞定”了所有常用的整数处理功能,而对于.NET的System.In32结构,好奇的朋友不妨用Reflector去查看一下相关的源码,会发现System.Int32在内部许多地方使用了Number类所封装的功能,还用到了NumberFormatInfo(提供数字的格式化信息)、CultureInfo(提供当前文化信息)等相关类型,如果再算加上一堆的接口,那真是“相当地”复杂。

         比对一下Java平台与.NET平台,往往会发现在许多地方Java封装得较少。

         从应用程序开发角度来看,不少地方Java在使用上不如.NET方便。就拿本文所涉及的非常常见的整数类型及其运算而言,相信大家都看到了,使用Java编程需要留心这个“Intege对象缓存r”的陷阱,而.NET则很贴心地把这些已发现的陷阱(.NET设计者说:当然肯定会有没发现的陷阱,但那就不关我事了)都盖上了“厚厚”的井盖,让开发者很省心,因而带来了较高的开发效率和较好的开发体验。

         但另一方面,Java的JDK代码一览无余,是开放的,你要探索其技术内幕,总是很方便,这点还是比较让人放心。

         .NET则相对比较封闭,总是遮遮掩掩,想一览其庐山真相还真不容易,而且我感觉它为开发者考虑得太周到了,服务得太好了,这不见得是一件好事。因为人性的弱点之一就是“好逸恶劳”,生活太舒服了,进取精神就会少掉不少,.NET开发者很容易于不知不觉中养成了对技术不求甚解的“恶习”,因为既然代码能够正常工作,那又何必费心地去追根问底?但话又说回来,如果仅满足于知其然,又怎会在技术上有所进步和提高?等到年纪一大,就被年轻人给淘汰了。而这种现象的出现,到底应该怪微软,怪周遭的环境,还是自己呢?

 

 

CentOS 环境 sngrep 安装及使用 在呼叫中心类应用开发过程中,经常需要对 SIP 信令抓包,分析排查问题。通常抓包的工具非常多样,如 Wireshark、tcpdump、ngrep 等都是可选项,但是针对 SIP 信令的抓包,sngrep 则更为好用。因为 sngrep 不仅提供了图形界面,还会将一通会话的 SIP 信令关联汇总,非常直观执行以下命令下载 的相关依赖库 1.2 添加 sngrep 的源并导入 执行下面的命令新增一个源仓库配置文件 然后在该文件中写入以下配置内容 执行命令导入源仓库的公钥 1.3 安装 sngrep 阅读详情

相关推荐

深信服aCloud虚拟存储VS3.0实战:从数据分片到仲裁机制的全流程解析

本文深度解析了深信服aCloud虚拟存储VS3.0的核心架构与生产级实践。从数据分片、条带化写入、多副本机制到智能缓存分层,详细阐述了其如何实现高性能与高可靠性的平衡。同时,深入剖析了动态均衡、平滑扩容以及故障恢复与仲裁机制,为运维人员和技术决策者提供了在超融合基础架构(HCI)中部署和管理虚拟存储的实战指南。

net55的博客 588

C# 与 JAVA 常见代码对照表

在C#中,Map使用Dictionary来实现,以对象的某个属性为key,另一属性为value,转Map。在C#中,List只有一种实现,即List。java: key重复,后来者取而代之。java: key重复,后来者取而代之。

飞鸿踏雪泥的博客 859

深入解析uncompyle6反编译pyc文件及常见错误修复指南

本文深入解析了使用uncompyle6工具反编译Python字节码文件(.pyc)的完整流程。针对实践中最高频的KeyError和Python版本范围限制两大错误,提供了详细的修复方案与步骤指南,并分享了处理复杂反编译结果的高级技巧与安全实践,是进行代码恢复、调试与分析的重要参考。

uber9的博客 534

c#和java的一些语法区别

C#中有无符号数,Java没有。 C#中有值类型,且可自己定义值类型的结构体(struct)。 Java中的基本类型(或叫基元类型)即为值类型,但Java没有结构体,所以不能自定义值类型。 C#中的值类型(包括所有基本类型)间接继承自Object,有自己的方法可以调用;Java中的值类型(即基本类型)不继承自Object,只是简单的数据,没有方法可以调用。 C#中int等同于Sys

lingkaigood123的专栏 3255

三菱FX5U PLC与CCLINK模块通信配置全流程(附接线图与参数详解)

本文详细解析了三菱FX5U PLC与CCLINK模块的通信配置全流程,包括硬件接线规范、参数设置及软件编程方法。通过实战指南帮助工程师快速掌握FX5U与CCLINK模块的高效通信技术,提升工业自动化控制系统的稳定性和可靠性。

weixin_27014595的博客 430

Agv、Rgv 车辆控制调度系统开发第一篇

Agv、Rgv 车辆控制调度系统第一篇为什么要做这个系统先看作品从头讲起算法讲解编程语言从哪里开始继续深入预告 为什么要做这个系统 说白了是为了赚钱,在一个项目中发现公司买别人家的调度系统要几十万,还只是一个项目的实施,从那天起我就决定自己写一套,用了一年的时间写出来后,才发现根本卖不掉,卖不掉就卖不掉吧,反正我现在已经吧写这套系统当成了一种乐趣,如果不让我写了我反而不适应,但是没有人欣赏我的成果我反而很难受,所以决定吧这个系统的创作过程,写下来,给后面的人一些建议,少走点弯路。 先看作品 从头讲起 在

持续分享调度系统开发过程 2万+

c java 大小_C#/Java/C/C++基本类型所占大小及表示范围

C/C++的数据类型:一,整型Turbo C:[signed] int 2Byte//有符号数,-32768~32767unsigned int 2Byte //无符号数,只能表示整数0~65535[signed] short [int] 2Byteunsigned short [int] 2 Bytelong [int] 4 Byteunsigned long [int] 4 ByteVisua...

weixin_29587591的博客 625

WebDriverAgent 菜鸟解析篇

WebDriverAgent 是一个用于模拟移动设备浏览器的 Python 库,可以用来在 PC 上模拟移动设备的浏览器操作,从而进行自动化测试。下面是一个菜鸟对 WebDriverAgent 源码的解析篇,希望能对初学者有所帮助。

DJ355的博客 1222

[C#] C# 与 Java 的一些差异

这篇文章, 可以帮助你借助 C# 的知识快速入门 Java, 并且详细介绍 C# 与 Java 的重要差异 1. 数据类型 在 C# 中, 基本的数据类型都有别名, 例如字符串 String, 可以简写为 string, Int32 可以简写为 int, 但是在 Java 中, 不存在这些. 使用字符串, 必须要首字母大写, 使用布尔值必须要用 boolean. 在 C# 中, String 数据基本数据类型, 而在 Java 中, 严格来讲, 它不属于基本数据类型. Java 中的基本数据类型更像是.

诺尔的博客 464

实战避坑:基恩士KV8000 PLC与C#上位机链路通讯全流程实现(含ST代码+上位机源码)

本文详细讲解了基恩士KV8000 PLC与C#上位机的TCP链路通讯实现,从PLC端的ST代码编写、通讯配置,到上位机的通讯类封装、界面实现,再到实战避坑和性能优化,提供了完整的可复用方案。该方案已在实际产线项目中验证,支持实时数据采集和控制指令下发,稳定性和可靠性满足工业场景需求。

这里只有干货:从 Modbus 通信到 MES 对接,从 YOLO 训练到工控机部署,带你搞定工业软件开发全流程。 1176

YOLOv11改进 | 添加注意力篇 | 一文带你改进GAM、CBAM、CA、ECA等通道注意力机制和多头注意力机制

这篇文章给大家带来的改进机制是一个汇总篇,包含一些简单的注意力机制,本来一直不想发这些内容的(网上教程太多了,发出来增加文章数量也没什么意义),但是群内的读者很多都问我这些机制所以单独出一期视频来汇总一些比较简单的注意力机制添加的方法和使用教程,本文的内容不会过度的去解释原理,更多的是从从代码的使用上和实用的角度出发去写这篇教程。欢迎大家订阅我的专栏一起学习YOLO!YOLOv11改进系列专栏——本专栏持续复习各种顶会内容——科研必备目录一、本文介绍二、GAM2.1 GAM的介绍2.2 GAM的核心代码。

Snu77的博客 5152

Integer类

一,概述和使用 1,包装一个对象中的原始类型int的值 方法名 说明 – – – –

qq_53009248的博客 838

Qt5.15.7编译报错问题汇总:python2安装环境导致的问题

导致编译生成的:RegExpJitTables.h文件大小为0。RegExpJitTables.h 能生成且大小不为0KB。可以看到,正确的python路径,执行编译路径后。再执行 configure XXX…尝试直接改,将其改为正确的路径。

MusicScore的博客 1439

C# int挑战Java Integer

但从探索技术内幕而言则大不一样,Java使用Integer一个类就“搞定”了所有常用的整数处理功能,而对于.NET的System.In32结构,好奇的朋友不妨用Reflector去查看一下相关的源码,会发现System.Int32在内部许多地方使用了Number类所封装的功能,还用到了NumberFormatInfo(提供数字的格式化信息)、CultureInfo(提供当前文化信息)等相关类型,如果再算加上一堆的接口,那真是“相当地”复杂。将Java的设计与.NET(以C#为例)的设计作个比较是有趣的。

nDc6s38Xf的博客 163

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

C#之int挑战Java之Integer

<br /><br /> <br />注:<br />         此文是我为本人拙著《.NET 4.0面向对象编程漫谈》所新写的扩充阅读材料。<br />         本文涉及到一些JVM原理和Java的字节码指令,推荐感兴趣的读者阅读一本有关JVM的经典书籍《深入Java虚拟机(第2版)》,将它与我在《.NET 4.0面向对象编程漫谈》中介绍的CLR原理与IL汇编指令作个对比,相信读者会有一定的启发。而仔细对比两个类似事物的异同,是很有效的学习方法之一。<br />         今后我还将在

2780

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

C#之int挑战Java之Integer(转)

可能有些图会看不到,可以到转载处去阅读:http://kb.cnblogs.com/page/79961/     本文涉及到一些JVM原理和Java的字节码指令,推荐感兴趣的读者阅读一本有关JVM的经典书籍《深入Java虚拟机(第2版)》,将它与我在《.NET 4.0面向对象编程漫谈》中介绍的CLR原理与IL汇编指令作个对比,相信读者会有一定的启发。而仔细对比两个类似事物的异同,是很有效...

先相信你自己,然后别人才会相信你。 532

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

一起谈.NET技术,C#之int挑战Java之Integer

  本文涉及到一些JVM原理和Java的字节码指令,推荐感兴趣的读者阅读一本有关JVM的经典书籍《深入Java虚拟机(第2版)》,将它与我在《.NET 4.0面向对象编程漫谈》中介绍的CLR原理与IL汇编指令作个对比,相信读者会有一定的启发。而仔细对比两个类似事物的异同,是很有效的学习方法之一。   今后我还将在个人博客上放出其他的文章,希望能帮助书的读者开拓视野,启发思考,大家一起探讨技术的奥秘...

weixin_34234823的博客 95

C#之int与Java之Integer的区别

本文涉及到一些JVM原理和Java的字节码指令,推荐感兴趣的读者阅读一本有关JVM的经典书籍《深入Java虚拟机(第2版)》,将它与我在《.NET 4.0面向对象编程漫谈》中介绍的CLR原理与IL汇编指令作个对比,相信读者会有一定的启发。而仔细对比两个类似事物的异同,是很有效的学习方法之一。 1 奇特的程序输出           前段时间,一个学生给我看了一段“非常诡异”的Java代码:

小小人生的专栏 1142

java中integer valueOf,java中的Integer.valueOf()是否在C#中转换为int.Parse()?(Does Integer.valueOf() in java tra...

java中的Integer.valueOf()是否在C#中转换为int.Parse()?(Does Integer.valueOf() in java translate to int.Parse() in C#?)我正在尝试从C#背景学习java! 我在旅程中发现了一些细微差别,比如C#没有Integer作为引用类型,它只有int作为基本类型; 这让我怀疑这个翻译是否正确!String line...

weixin_39796533的博客 264

Integer、new Integer()和int的区分与比较

通过基本概念区分: 1、Integer 是 int 的包装类,int 则是 java 的一种基本数据类型; 2、Integer 变量必须实例化后才能使用,而int变量不需要 ; 3、Integer 实际是对象的引用,当new一个 Integer时,实际上是生成一个指针指向此对象;而 int 则是直接存储数据值 ; 4、Integer的默认值是null,int的默认值是0 Integ...

weixin_41804367的博客 733

10分钟讲清int 和 Integer 的区别_int和integer有什么区别

/ 抛出NullPointerException异常。// 抛出NullPointerException。System.out.println(“a不等于b”);System.out.println(“a等于b”);System.out.println(“a等于b”);System.out.println(“a等于b”);

2401_89083484的博客 438

int ,integer 源码解析

先来看一个经典的int,integer 的面试题。 public void main (String[] args){ int a=1,b=2; system.out.println(&quot;a= &quot;+a+&quot; b= &quot;+b); swap(a,b); system.out.println(&quot;a= &quot;+a+&quot; b= &quot;+b); } pu

攻防人生3722的博客 738
上一篇: 再谈MSDN Library For Visual Studio 2010
下一篇: 《.NET 4.0面向对象编程漫谈》前言及配套资源包发布
bitfan
博客等级 码龄26年 4298粉丝 243原创
评论 95
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值