计算机基础系列文章

计算机基础(一):ASCll、GB2312、GBK、Unicode、UTF-32、UTF-16、UTF-8深度解析

计算机基础(二):轻松理解二进制、八进制、十进制和十六进制

计算机基础(三):深入解析Java中的原码、反码、补码

目录

  • 引言
  • 一、 基础概念:三种编码的诞生背景
    • 1、原码
    • 2、反码
    • 3、补码 🏆 - Java的选择
  • 二、 Java的坚定选择:补码一统天下
    • 1、为什么Java整数表示使用补码?
    • 2、为什么byte的范围是-128到127,而不是-127到127?
  • 三、 眼见为实:Java代码验证补码
  • 总结

引言

  在Java的世界里,我们每天都在与整数打交道:int age = 30;long balance = 1000000L;。但你是否思考过,这些数字在计算机内部的真实形态?理解原码、反码、补码不仅是计算机科学的基础,更是深入Java底层、避免隐蔽bug的关键。本文将带你彻底掌握这些二进制表示法的奥秘及其在Java中的实际应用。


一、 基础概念:三种编码的诞生背景

计算机只能处理二进制(0和1)。如何表示有符号整数(正数、负数)?工程师们设计了三种方案

1、原码

  • 定义:最高位表示符号位(0=正数,1=负数),其余位表示数值的绝对值
  • 示例 (8位byte为例):
    • +5原码:0000 0101 (符号位0,绝对值5)
    • -5原码:1000 0101 (符号位1,绝对值5)
  • 优点:人类直观,理解容易
  • 致命缺陷:
    • 存在两种零+0的原码为00000000-0的原码为10000000( 以一个字节长表示 ),浪费表示范围,逻辑上冗余
    • 加减运算复杂:正数和负数相加,数值部分实际上是相减,符号取决于绝对值大者的符号,硬件不能直接相加符号位和数值位
      • 示例1:(+5) + (-5) = 0,程序直接运算❌
      • 原码的加法不支持符号修正(不能自动让结果的符号与数值正确对应)
            0000 0101  (+5)+ 1000 0101  (-5)-----------------1000 1010  结果为 -10
        
      • 示例2:(-5) + (+3) = -2,程序直接运算❌
            1000 0101  (-5)+ 0000 0011  (+3)-----------------1000 1000  结果为 -8
        
      • 示例3:(-5) + (-5) = -10,程序直接运算❌
      • 原码的加法不支持进位消除(多出的进位被丢弃,不影响结果)
            1000 0101  (-5)+ 1000 0101  (-5)-----------------1 0000 1010  结果为 10(注意:最高位溢出了1位舍弃)
        

2、反码

  • 定义:
    • 正数:反码 = 原码
    • 负数:反码 = 负数原码符号位不变,数值位按位取反,或者更简单点正数原码全部按位取反
  • 示例 (8位byte为例):
    • +5反码:0000 0101 (同原码)
    • --5反码:1111 1010 (-5的原码1000 0101按位取反,符号位不变或者+5原码全部按位取反)
  • 遗留问题:
    • 两种零依然存在+0反码为0000 0000-0反码1111 1111(+0的原码按位取反)
    • 循环进位:计算结果最高位有进位时,需要把进位“回加”到最低位(称为“末位加1”或“循环进位”),硬件实现仍不理想
      • 示例1:(+5) + (-5) = 0,程序直接运算✅
      • 反码的加法在数值上可以看作正确,但从表达角度来看,有点不完美
            0000 0101  (+5)+ 1111 1010  (-5)-----------------1111 1111  结果是反码,符号位不变其他按位取反,原码就是1000 0000也就是-0(负零)
        
      • 示例2:(-5) + (+3) = -2,程序直接运行✅
            1111 1010  (-5)+ 0000 0011  (+3)-----------------1111 1101  结果是反码,原码为1000 0010也就是-2
        
      • 示例3:(-5) + (-5) = -10,程序直接运行❌
      • 反码的加法需要循环进位
            1111 1010  (-5)+ 1111 1010  (-5)-----------------1 1111 0100  结果是反码(注意:最高位溢出了1位舍弃),最高位进位:1(需循环加回最低位)1111 0100+         1-----------------1111 0101 这里还是反码,原码为1000 1010也就是-10
        

3、补码 🏆 - Java的选择

  • 定义:
    • 正数:补码 = 原码
    • 负数:补码 = 反码 + 1
  • 示例 (8位byte为例):
    • +5补码:0000 0101
    • -5补码:+5的原码按位取反获得反码1111 1010,再加1获得补码1111 1011
  • 核心优势 (完美解决前两者问题):
    • 唯一的零:+0补码为0000 0000-0补码是+0的原码全部按位取反再加1得到还是0000 0000,溢出一位舍去
    • 减法变加法:A - B = A + (-B) 直接成立,无需额外判断符号位处理循环进位。硬件只需一套加法电路
      • 示例1:(+5) + (-5) = 0,程序直接运算✅
      • 补码加法支持进位消除(多出的进位被丢弃,不影响结果)
            0000 0101  (+5)+ 1111 1011  (-5)-----------------1 0000 0001  结果是补码,先减1获得反码0000 0000,也就是0
        
      • 示例2:(-5) + (+3) = -2,程序直接运算✅
            1111 1011  (-5)+ 0000 0011  (+3)-----------------1111 1110  结果是补码,先减1获得反码1111 1101,符号位不变其他按位取反获取原码1000 0010,也就是-2
        
      • 示例3:(-5) + (-5) = -10,程序直接运算✅
            1111 1011  (-5)+ 1111 1011  (-5)-----------------1 1111 0110  结果为是补码,先减1获得反码1111 0101,符号位不变其他按位取反获得原码1000 1010,也就是-10
        

二、 Java的坚定选择:补码一统天下

1、为什么Java整数表示使用补码?

  • 补码解决了原码和反码的固有问题(双零复杂运算),简化了CPU硬件设计,提高了运算效率
    1. 最大优势正数和负数的加法、减法可以统一处理(解决痛点:原码需要判断正负)
    2. 补码中只有一个 0(解决痛点:原码和反码有+0和-0,也需要单独判断)
    3. 补码支持进位消除(解决痛点:符号参加运行,多出的进位丢弃,不影响结果,反码需要循环进位)
  • Java的所有整数类型(byte, short, int, long)均使用补码表示!这是现代计算机体系结构的标准

2、为什么byte的范围是-128到127,而不是-127到127?

8 位二进制的表示能力

  • Byte 类型占用 8 位(1 字节)存储空间,共有2^8 = 256种可能的二进制组合
  • 在补码体系中,最高位为符号位(0 正 1 负),剩余 7 位表示数值

补码表示法的规则

  • 正数和零:补码与原码相同,范围是 0000 0000(0)到 0111 1111(127),共 128 个值
  • 负数:补码 = 原码取反 + 1,范围是 1000 0001(-127)到 1111 1111(-1),占 127 个值
  • 关键点:1000 0000 被定义为 -128
二进制(补码)十进制值
1000 0000-128
1000 0001-127
1000 0010-126
...
1111 1110-2
1111 1111-1
0000 00000
0000 00011
0000 00102
...
0111 1110126
0111 1111127

为何不是 -127 到 127?

  • 若范围设为 -127 到 127(含 0),仅能表示 127 + 128 = 255 127 + 128 = 255 127+128=255 个值,无法覆盖全部 256 种组合
  • 补码的连续性要求:将 1000 0000 分配给 -128 后:
    • 数值序列形成闭环:127(0111 1111)+1 溢出为 -128(1000 0000),实现连续循环
    • 若不这样设计,会浪费一个二进制组合(1000 0000),且破坏数值连续性,-127(1000 0001)-1正好是-128(1000 0000

编程语言中的实际表现

  • Byte.MAX_VALUE = 127,Byte.MIN_VALUE = -128
  • 赋值超出范围(如 byte b = 128;)会触发编译错误,如127 + 1 = -128(因 0111 1111 + 1 = 1000 0000

三、 眼见为实:Java代码验证补码

  • Integer.toBinaryString(int i) 方法会返回一个整数补码表示的字符串(省略前导零,负数显示完整的32位,int占4个字节
public class ComplementDemo {public static void main(String[] args) {int positive = 5;int negative = -5;// 打印正数5的二进制(补码,省略前导零)System.out.println(Integer.toBinaryString(positive)); // 输出: 101// 打印负数-5的二进制(32位完整补码)System.out.println(Integer.toBinaryString(negative)); // 输出: 1111 1111 1111 1111 1111 1111 1111 1011}
}

解读负数输出:

  • 11111111111111111111111111111011 就是 -5 的 32 位补码
  • 它是由 +5 (00000000_00000000_00000000_00000101) 按位取反 (11111111_11111111_11111111_11111010)
  • 再加 1 得到的 (11111111_11111111_11111111_11111011)

总结

  • 原码:直观但有双零,运算复杂(历史概念)
  • 反码:试图改进运算,仍有双零和循环进位问题(历史概念)
  • 补码 (Java的选择):统一零表示,完美支持 A - B = A + (-B),硬件实现高效简单,是现代计算机整数表示的标准
  • Java实践:byte, short, int, long 均用补码。Integer.toBinaryString() 可查看补码形式

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/diannao/87695.shtml
繁体地址,请注明出处:http://hk.pswp.cn/diannao/87695.shtml
英文地址,请注明出处:http://en.pswp.cn/diannao/87695.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

phpstudy无法启动mysql,一启动就关闭,完美解决

phpstudy无法启动mysql,一启动就关闭,完美解决 phpstudy的mysql无法启动,一启动就关闭如何解决。 问题出现的原因:phpstudy自带的mysql,可能与之前单独安装的mysql发生冲突。(之前安装的mysql已经占用3306端口) 解决方…

mysql中的<>和!=

在MySQL中&#xff0c;<> 运算符表示 不等于。它与 ! 运算符功能完全相同&#xff0c;都是用于比较两个表达式是否不相等。 SELECT * FROM table_name WHERE column_name <> value;当 column_name 的值不等于 value 时&#xff0c;返回该行当值相等或为 NULL 时&a…

C#学习日记

命名空间 知识点一 命名空间基本概念 概念 命名空间是用来组织和重用代码的 作用 就像是一个工具包&#xff0c;类就像是一件一件的工具&#xff0c;都是申明在命名空间中的 知识点二 命名空间的使用 基本语法 namespace 命名空间名 {类类 } namespace MyGame {class GameO…

第八十二篇 大数据开发基础:树形数据结构深度解析与实战指南(附创新生活案例)

目录 一、树的本质&#xff1a;层次化数据组织二、生活中的树形智慧&#xff1a;无处不在的层次案例1&#xff1a;图书馆图书分类系统案例2&#xff1a;电商平台商品类目树案例3&#xff1a;城市行政区域划分 三、大数据中的核心树结构1. B树&#xff1a;数据库索引的脊梁2. 决…

从0开始学计算机视觉--Day1--计算机视觉的起源

我们经常能听到计算机视觉这个词语&#xff0c;像数字图像处理&#xff0c;算法设计&#xff0c;深度学习等领域。但很少有人会先去了解清楚这门知识&#xff0c;而是用到什么再学什么&#xff0c;虽然这在项目进度上能节省不少时间&#xff0c;但有时候囫囵吞枣式地学习容易落…

简单的 ​Flask​ 后端应用

from flask import Flask, request, jsonify, session import os app Flask(__name__) app.secret_key os.urandom(24) users { 123: admin, admin: admin } # 登录接口 app.route(/login, methods[POST]) def login(): data request.get_json() username data.get(usern…

spring-webmvc @PathVariable 典型用法

典型用法 基础用法 GetMapping("/users/{id}") public String getUser(PathVariable Long id) {return "User ID: " id; } 请求&#xff1a;/users/1001 输出&#xff1a;User ID: 1001---- GetMapping("/users/{userId}/orders/{orderId}") …

LVS+Keepliaved高可用群集

目录 keepalived双击热备基础知识1.keepallived概述及安装keepalived的热备方式 2.使用keepalived实现双机热备 案例1.基础主备调度器环境配置2.配置主调度器3.配置从调度器4.配置两台节点服务器5.测试 keepalived双击热备基础知识 Keepalived 起初是专门针对 LVS 设计的一款强…

在Unreal Engine 5(UE5)中,Get PlayerPawn和Get PlayerController的区别以及如何计算玩家和目标之间的距离。

一、两者区别 在Unreal Engine 5&#xff08;UE5&#xff09;中&#xff0c;获取玩家的位置信息通常有两种方式&#xff1a;通过PlayerPawn或通过PlayerController。具体使用哪一个取决于你想要获取的是哪个实体的位置。 1.Get Player Pawn&#xff1a; PlayerPawn是玩家实际…

linux线程同步

互斥锁 同步与互斥概述** 现代操作系统基本都是多任务操作系统&#xff0c;即同时有大量可调度实体在运行。在多任务操作系统中&#xff0c;同时运行的多个任务可能&#xff1a; 都需要访问/使用同一种资源 多个任务之间有依赖关系&#xff0c;某个任务的运行依赖于另一个任…

Spring 的IoC 和 AOP

第一部分&#xff1a;关于 IoC (控制反转) 1. 核心思想 (What & Why) 首先&#xff0c;我会先解释 IoC 的核心思想&#xff0c;而不是直接讲技术。 “IoC&#xff0c;即控制反转&#xff0c;它是一种重要的设计思想&#xff0c;而不是一个具体的技术。它的核心是将传统上…

[实战] Windows 文件读写函数 `ReadFile()` 和 `WriteFile()` 的阻塞与非阻塞操作详解(含完整C语言示例)

Windows 文件读写函数 ReadFile() 和 WriteFile() 的阻塞与非阻塞操作详解&#xff08;含完整C语言示例&#xff09; 在 Windows 平台进行文件或设备&#xff08;如串口、管道&#xff09;编程时&#xff0c;ReadFile() 和 WriteFile() 是最常用的两个 API 函数。它们既可以以…

Singularity 安装

Singularity 是什么? 核心功能:用于创建/运行容器(将应用+依赖打包的独立环境)。 与 Docker 的区别:专为 HPC(高性能计算)设计,无需后台守护进程,支持非 root 运行容器(但安装本身需 root 权限)。 适用于在具有 root 权限的计算机上从源代码安装 Singularity。…

辩证视角下 “辫子戏” 的文化反思与价值重构

前阵子播出的《人生若如初见》刻意美化晚清封建统治阶级&#xff0c;淡化甚至掩盖清政府闭关锁国、丧权辱国、残酷压迫民众等历史真相&#xff0c;将本应批判反思的腐朽统治包装成值得歌颂的对象&#xff1b;在历史叙事上&#xff0c;或通过虚构、篡改重要历史事件和人物形象&a…

MCP-server

&#x1f4a1; 说明&#xff1a;该模块是 MCP 服务器的 数据中继层&#xff0c;确保安全高效地从分布式来源获取模型及其上下文&#xff0c;适用于边缘计算和联邦学习场景。若要查看完整代码&#xff0c;建议直接访问 GitHub 链接

第3讲、LangChain性能优化:上下文缓存与流式响应实战指南

目录 概述上下文缓存优化流式响应优化复杂对话场景性能优化用户体验优化策略完整实现示例性能监控与调优总结 概述 在复杂对话场景中&#xff0c;大型语言模型面临着响应延迟、重复计算、上下文管理等挑战。本文将详细介绍如何通过LangChain的上下文缓存和流式响应功能来优化…

http中GET和POST、PUT之间的区别

在HTTP协议中&#xff0c;GET、POST和PUT是三种最常用的请求方法&#xff0c;它们的主要区别如下&#xff1a; 1. GET 用途&#xff1a;用于请求资源&#xff08;查询数据&#xff09;&#xff0c;不应修改服务器状态。 参数传递&#xff1a;通过URL的查询字符串&#xff08;…

埃夫特各种系列机器人运动学建模、轨迹规划和工作空间求解

要求&#xff1a; 1.理论分析 1.1 正向运动学&#xff1a;根据D-H法完成机器人的正向运动学&#xff08;数学建模后基于Matlab计算公式&#xff09;&#xff1b; 1.2 工作空间分析&#xff1a;根据正向运动学结果&#xff0c;运用 MATLAB进行工作空间分析&#xff0c;完成工…

VUE3 路由的跳转方法

Routerlink跳转方法 name属性对应了路由文件配置的name path属性对应了路由的路径 <RouterLink to"/login">点击跳转登陆</RouterLink> <RouterLink :to"{name:login}">点击跳转登陆</RouterLink> <RouterLink :to"{pat…

数据库中间件ShardingSphere5

一、高性能架构模式 数据库集群&#xff0c;第一种方式“读写分离”&#xff0c;第二种方式“数据库分片”。 1.1 读写分离架构 读写分离原理&#xff1a;将数据库读写操作分散到不同的节点上。 读写分离的基本实现&#xff1a; 主库负责处理事务性的增删改操作&#xff0c…