java中整型的大端和小端

比如在Java中声明了一个 int变量,这个变量在栈内存中分配内存地址,那当int值保存到栈内存中时是用大端还是小端?如何验证?

在 Java 中,int 类型变量在栈内存中的存储方式(大端或小端)是由 底层硬件架构JVM 的实现 决定的。一般来说:

  1. x86 和 x86-64 平台上的 JVM 通常会按照 小端序 存储。
  2. ARM 平台可能会采用大端或小端,取决于其配置。

验证一个 int 变量在栈内存中是大端还是小端存储,需要通过一些间接方式,因为 Java 不允许直接操作内存地址。可以借助 JNI(Java Native Interface) 或 Unsafe 类来实现。

方法 1:通过 JNI 检查栈内存中的字节顺序

我们可以通过 JNI 编写一个本地方法来直接读取栈内存中保存的 int 变量的字节序。

class EndiannessChecker {// 声明本地方法external fun checkEndianness(value: Int)companion object {init {// 加载本地库System.loadLibrary("endianness")}}
}fun main() {val testValue = 0x12345678 // 一个明确的 32 位整数EndiannessChecker().checkEndianness(testValue)
}
#include <jni.h>
#include <stdio.h>// 实现 JNI 方法
extern "C"
JNIEXPORT void JNICALL
Java_EndiannessChecker_checkEndianness(JNIEnv *env, jobject obj, jint value) {unsigned char *bytePointer = (unsigned char *)&value;printf("Integer value in Hex: 0x%x\n", value);printf("Bytes in memory: ");for (int i = 0; i < sizeof(value); i++) {printf("0x%02x ", bytePointer[i]);}printf("\n");// 判断字节顺序if (bytePointer[0] == 0x78) {printf("Stack stores integers in Little-Endian order\n");} else if (bytePointer[0] == 0x12) {printf("Stack stores integers in Big-Endian order\n");} else {printf("Unknown endianness\n");}
}

运行结果:

  • 如果是小端存储:

    Integer value in Hex: 0x12345678
    Bytes in memory: 0x78 0x56 0x34 0x12 
    Stack stores integers in Little-Endian order
    
  • 如果是大端存储:

    Integer value in Hex: 0x12345678
    Bytes in memory: 0x12 0x34 0x56 0x78 
    Stack stores integers in Big-Endian order
    

在一台Android设备上运行,结果显示为小端。

方法2:用 Unsafe 验证字节序

import sun.misc.Unsafe
import java.lang.reflect.Fieldobject UnsafeHelper {val unsafe: Unsafeinit {val unsafeField: Field = Unsafe::class.java.getDeclaredField("theUnsafe")unsafeField.isAccessible = trueunsafe = unsafeField.get(null) as Unsafe}
}fun main() {val unsafe = UnsafeHelper.unsafe// 定义一个整数变量val testValue = 0x12345678println("Test Value (Hex): 0x${testValue.toString(16)}")// 在堆内存中分配 4 个字节来存储整数val memoryAddress = unsafe.allocateMemory(4)try {// 将整数值写入内存unsafe.putInt(memoryAddress, testValue)// 逐字节读取并打印内存中的值println("Bytes in memory:")for (i in 0 until 4) {val byteValue = unsafe.getByte(memoryAddress + i).toInt() and 0xFFprint("0x${byteValue.toString(16).padStart(2, '0')} ")}println()// 根据第一个字节的值判断字节序val firstByte = unsafe.getByte(memoryAddress).toInt() and 0xFFwhen (firstByte) {0x78 -> println("System is Little-Endian")0x12 -> println("System is Big-Endian")else -> println("Unknown Endianness")}} finally {// 释放分配的内存unsafe.freeMemory(memoryAddress)}
}

在Windows中运行,结果如下:

Test Value (Hex): 0x12345678
Bytes in memory:
0x78 0x56 0x34 0x12 
System is Little-Endian

在Android中没有Unsafe类。

方法3:使用ByteOrder.nativeOrder()最简单,在Windows中在Android中皆可运行:

println(ByteOrder.nativeOrder())

我在Windows和Android中运行结果均为:LITTLE_ENDIAN

当我们使用一些对象来存储整数值时,它会用大端还是小端呢?这个不用猜,直接看JDK文档即可,比如,使用ByteBuffer可以把int保存到字节数组中,如下:

fun main() {val byteBuffer = ByteBuffer.allocate(4)byteBuffer.asIntBuffer().put(0x12345678)
}

在ByteBuffer中有一个order()函数可以返回缓冲区的字节顺序,文档描述如下:

获取此缓冲区的字节顺序。

在读写多字节值以及为此字节缓冲区创建视图时使用该字节顺序。新创建的字节缓冲区的顺序始终为 BIG_ENDIAN。

所以,我们创建的ByteOrder默认使用大端。实验如下:

fun main() {val byteBuffer = ByteBuffer.allocate(4)byteBuffer.asIntBuffer().put(0x12345678)// 以16进制的方式打印byteBuffer中的每个字节for (i in 0 until byteBuffer.limit()) {print("0x${String.format("%02X", byteBuffer.get(i))} ")}
}

运行结果如下:

0x12 0x34 0x56 0x78 

我们也可以改变ByteBuffer的字节顺序:

fun main() {val byteBuffer = ByteBuffer.allocate(4)byteBuffer.order(ByteOrder.LITTLE_ENDIAN)byteBuffer.asIntBuffer().put(0x12345678)// 以16进制的方式打印byteBuffer中的每个字节for (i in 0 until byteBuffer.limit()) {print("0x${String.format("%02X", byteBuffer.get(i))} ")}
}

运行结果如下:

0x78 0x56 0x34 0x12 

另外写数据还有输出流,当写出整型数据时,使用大端还是小端,查看JDK文档即可,比如:DataOutputStream.writeInt(0x12345678),对于该函数,文档描述如下:

将一个 int 值以 4-byte 值形式写入基础输出流中,先写入高字节。

先写高字节,所以它是大端。

如果就想以小端方式写怎么办?可以自定义一个输出流,以小端方式写即可,如下:

public class LittleEndianOutputStream extends FilterOutputStream {public LittleEndianOutputStream(OutputStream out) {super(out);}public void writeInt(int v) throws IOException {out.write(v & 0xFF);        // 写入最低字节out.write((v >>> 8) & 0xFF); // 写入次低字节out.write((v >>> 16) & 0xFF); // 写入次高字节out.write((v >>> 24) & 0xFF); // 写入最高字节}
}

反过来,如果要以大端写,无非就是调一下顺序:

public final void writeInt(int v) throws IOException {out.write((v >>> 24) & 0xFF);out.write((v >>> 16) & 0xFF);out.write((v >>> 8) & 0xFF);out.write((v) & 0xFF);
}

是好用的还是使用ByteBuffer,因为可以给这个ByteBuffer指定ByteOrder为大端或小端。

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

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

【汇编语言】标志寄存器(一) —— 标志寄存器中的标志位:ZF、PF、SF、CF、OF 一网打尽

前言 &#x1f4cc; 汇编语言是很多相关课程&#xff08;如数据结构、操作系统、微机原理&#xff09;的重要基础。但仅仅从课程的角度出发就太片面了&#xff0c;其实学习汇编语言可以深入理解计算机底层工作原理&#xff0c;提升代码效率&#xff0c;尤其在嵌入式系统和性能优…

【C++】priority_queue优先队列

大家好&#xff0c;我是苏貝&#xff0c;本篇博客带大家了解C的string类的priority_queue优先队列&#xff0c;如果你觉得我写的还不错的话&#xff0c;可以给我一个赞&#x1f44d;吗&#xff0c;感谢❤️ 目录 1. 介绍2. 仿函数(A) 介绍(B) 控制比较逻辑 3. priority_queue和…

Python3 operator 模块

Python2.x 版本中&#xff0c;使用 cmp() 函数来比较两个列表、数字或字符串等的大小关系。 Python 3.X 的版本中已经没有 cmp() 函数&#xff0c;如果你需要实现比较功能&#xff0c;需要引入 operator 模块&#xff0c;适合任何对象&#xff0c;包含的方法有&#xff1a; o…

短视频矩阵系统开发|技术源代码部署

短视频矩阵系统通过多账号运营管理、多平台视频智能分发等功能&#xff0c;助力企业实现视频引流、粉丝沉淀和转化。 短视频矩阵系统是一种创新的营销工具&#xff0c;它整合了多账号管理、视频智能分发、数据可视化等多种功能&#xff0c;为企业在短视频领域的发展提供了强大…

YOLOV11 快速使用教程

概述 这里主要记录使用NVIDIA GPU pytorch 检测系列模型的快速使用方式&#xff0c;可以快速解决一些工业应用的问题&#xff0c;比如&#xff1a;无网、数据大需要改路径、需要记录不同实验结果等问题。 安装 参考官网&#xff0c;自己安装好Python > 3.8和pytorch >…

git修改某次commit(白痴版)

第一步 在bash窗口运行 git rebase --interactive commitId^ 比如要改的commitId是 abcedf git rebase --interactive abcedf^键盘 按 i 或者 ins 进入编辑状态 进入insert 编辑状态 在bash窗口手动把对应commit前面的pick改为e或edit 按 esc 进入退出程序 输入 :wq 保存退出…

AI 建站:Durable

网址&#xff1a;https://app.durable.co 步骤 1) 登录 2&#xff09;点击创建新业务 3&#xff09;填写信息后&#xff0c;点击创建 4&#xff09;进入业务 5&#xff09;生成网站 6&#xff09;生成完成后不满意的话可以自己调整 7&#xff09;点击保存 8&#xff09;发布 …

网络原理之 TCP 协议

目录 1. TCP 协议格式 2. TCP 原理 (1) 确认应答 (2) 超时重传 (3) 连接管理 a) 三次握手 b) 四次挥手 (4) 滑动窗口 (5) 流量控制 (6) 拥塞控制 (7) 延时应答 (8) 捎带应答 3. TCP 特性 4. 异常情况的处理 1) 进程崩溃 2) 主机关机 (正常流程) 3) 主机掉电 (…

Python爬虫之selenium库驱动浏览器

目录 一、简介 二、使用selenium库前的准备 1、了解selenium库驱动浏览器的原理 &#xff08;1&#xff09;、WebDriver 协议 &#xff08;2&#xff09;、 浏览器驱动&#xff08;Browser Driver&#xff09; &#xff08;3&#xff09;、 Selenium 客户端库 &#xff0…

Vite+Vue3项目实战:组件化开发与通信指南

一、典型的ViteVue3项目结构 续上文成功创建Vue3项目的脚手架&#xff0c;通过visual Studio Code软件打开刚刚创建的文件夹&#xff0c;将会看到这样一个项目结构。 使用Vite构建Vue3项目时&#xff0c;项目结构通常遵循一定的组织规则&#xff0c;以保持代码的清晰和可维护性…

汽车免拆案例 | 2007款宝马650i车发动机偶尔无法起动

故障现象 一辆2007款宝马650i车&#xff0c;搭载N62B48B发动机&#xff0c;累计行驶里程约为26万km。车主反映&#xff0c;发动机偶尔无法起动&#xff0c;故障频率较低&#xff0c;十几天出现1 次&#xff0c;且故障出现时起动机不工作。 故障诊断  接车后试车&#xff0c;…

团队管理中如何做好目标管理

团队管理中的目标管理是确保团队高效运行的核心要素之一。 在目标管理中&#xff0c;清晰的目标设定、合理的资源分配、实时的跟踪与反馈机制是成功的关键。首先&#xff0c;设定SMART目标&#xff08;具体、可衡量、可达成、相关性强、时间限定&#xff09;能够有效聚焦团队的…

【力扣热题100】—— Day4.反转链表

你不会永远顺遂&#xff0c;更不会一直年轻&#xff0c;你太安静了&#xff0c;是时候出发了 —— 24.12.2 206. 反转链表 给你单链表的头节点 head &#xff0c;请你反转链表&#xff0c;并返回反转后的链表。 示例 1&#xff1a; 输入&#xff1a;head [1,2,3,4,5] 输出&…

【AWS re:Invent 2024】一文了解EKS新功能:Amazon EKS Auto Mode

文章目录 一、为什么要使用 Amazon EKS Auto Mode&#xff1f;二、Amazon EKS自动模式特性2.1 持续优化计算成本2.2 迁移集群操作2.3 EKS 自动模式的高级功能 三、EKS Auto 集群快速创建集群配置四、查看来自 API 服务器的指标五、EKS 相关角色权限设置六、参考链接 一、为什么…

记事本建java及java命名规范

1.桌面开发&#xff1a;c# 2. 记事本建java&#xff1a; 以class的名称(类名)为名&#xff0c;名称.java 编译jdk&#xff1a;javac 名称.java 调动运行jre : java 名称 查看名称.java里面的内容&#xff1a;cat 名称.java java 的命名规范 大驼峰&#xff08;每个单词首…

过程管理系统(源码+文档+部署+讲解)

本文将深入解析“过程管理系统”的项目&#xff0c;探究其架构、功能以及技术栈&#xff0c;并分享获取完整源码的途径。 系统概述 过程管理系统是一款专为工业设计的综合管理平台&#xff0c;旨在通过集成各种管理流程和功能模块来提高管理效率和安全性。系统提供了从登录系…

期权懂|个股期权交割操作流程是什么样的?

期权小懂每日分享期权知识&#xff0c;帮助期权新手及时有效地掌握即市趋势与新资讯&#xff01; 个股期权交割操作流程是什么样的&#xff1f; 一、行权申报&#xff1a; 期权买方在行权日通过其经纪商提交行权指令&#xff0c;表明其决定行使期权权利。 二、行权匹配&#xf…

智能仓储:入库业务流程介绍

01 入库流程 入库业务流程&#xff0c;常见过程是这样的&#xff1a; 创建PO单 > 创建到货清单 > 核对货物 > 入库质检 > 货物贴标签 > 上架 > 库存同步 1、创建PO单 po单指的是的采购订单&#xff0c;比如采购了一车货品&#xff0c;这车的货品可以理解…

MySQL并发控制(一):幻读

假设有如下表结构&#xff1a; CREATE TABLE t(id int(11) NOT NULL,c int(11) DEFAULT NULL,d int(11) DEFAULT NULL,PRIMARY KEY (id),KEY c (c) ) ENGINEInnoDB;insert into t values(0,0,0),(5,5,5),(10,10,10),(15,15,15),(20,20,20),(25,25,25); 问&#xff1a;如果执行…

Ubuntu22.04中mysql8 rpm安装

1、安装依赖 sudo apt update sudo apt -y dist-upgrade sudo apt -y install vim net-tools wget gcc make cmake lrzsz sudo apt -y install libmecab2 libjson-perl 2、下载rpm文件 https://dev.mysql.com/downloads/mysql/ https://cdn.mysql.com//Downloads/MySQL-8.0/m…