龙空技术网

数值在内存中的存储

ittimeline 18

前言:

而今姐妹们对“内存中什么可以储存0或10”可能比较重视,各位老铁们都想要知道一些“内存中什么可以储存0或10”的相关知识。那么小编也在网上搜集了一些有关“内存中什么可以储存0或10””的相关内容,希望你们能喜欢,同学们一起来学习一下吧!

1 整数在内存的的存储1.1 一个字节存储的数据范围

数据分为有符号和无符号两种

①无符号数:不考虑负数,也就是只有0和正数

0000 0000 ~ 1111 1111转换成十进制也就是0 ~ 255

因此一个字节存储无符号数的数据范围是0~255之间的256个整数

② 有符号数:考虑负数,也就是包含负数,0和正数

一个字节整数原码、反码和补码取值范围

十进制数字

原码

反码

补码

+127

0111 1111

0111 1111

0111 1111

...

...

...

...

+4

0000 0100

0000 0100

0000 0100

+3

0000 0011

0000 0011

0000 0011

+2

0000 0010

0000 0010

0000 0010

+1

0000 0001

0000 0001

0000 0001

+0

0000 0000

0000 0000

0000 0000

-0

1000 0000

1111 1111

0000 0000

-1

1000 0001

1111 1110

1111 1111

-2

1000 0010

1111 1101

1111 1110

-3

1000 0011

1111 1100

1111 1101

-4

1000 0100

1111 1011

1111 1100

...

...

...

...

-126

1111 1110

1000 0001

1000 0010

-127

1111 1111

1000 0000

1000 0001

-128

1000 0000

正数部分:0000 0000 ~ 0111 1111, 转换成十进制就是 0 ~ 127负数部分:1000 0001 ~ 1111 1111, 转换成十进制就是 -127 ~ -1特殊值:1000 0000,转换成十进制就是 -128,最高位既是符号位,又是数值位

因此一个字节存储有符号数的数据范围是-128 ~ 127之间的256个整数

使用计算器查看-128的补码表示方式

① 切换到程序员

② 选择一个字节(Byte)

③ 输入负整数十进制-128

④ -128的二进制补码是1000 0000

1. 编辑ByteLimit.java

package net.ittimeline.java.core.foundational.syntax.variable.type.primitive;/** * 一个字节存储的数据范围 * * @author tony 18601767221@163.com * @version 2024/10/15 9:13 * @since Java21 */public class ByteLimit {    public static void main(String[] args) {        //byte对应的包装类是Byte        //调用Byte的静态常量(MAX_VALUE,MIN_VALUE)获取byte类型的取值范围        //调用Byte的静态常量BYTES获取byte类型占据的字节数        System.out.println("byte所能存储的最大值是" + Byte.MAX_VALUE +                " byte所能存储的最小值是" + Byte.MIN_VALUE + " byte占据的内存空间是" + Byte.BYTES + "字节");    }}

2. 运行ByteLimit.java

程序运行结果

说明:Java的byte类型占据1个字节的内存空间,而且用于存储有符号整数,因此取值范围是-128~127 之间的256个整数

1.2 不同整数类型数据在内存中的存储

1. 编辑IntegerTypeStorage.java

package net.ittimeline.java.core.foundational.syntax.variable.type.primitive;/** * 不同整数类型数据在内存中的存储 * * @author tony 18601767221@163.com * @version 2024/10/15 9:14 * @since Java21 */public class IntegerTypeStorage {    public static void main(String[] args) {        byte byteVar = 3;        System.out.println("byteVar = " + byteVar);        short shortVar = 3;        System.out.println("shortVar = " + shortVar);        int intVar = 3;        System.out.println("intVar = " + intVar);        long longVar = 3;        System.out.println("longVar = " + longVar);    }}

2. 运行IntegerTypeStorage.java

程序运行结果

说明:虽然打印输出四种整数类型的变量存储的变量值都是3,但是它们在内存中占据的空间不同,因此存储形式也是不同,数据在内存中都是以二进制形式存储

1.3 正整数25和负整数-25在内存中的存储

整数底层使用二进制补码形式存储,要了解补码需要先了解原码和反码

原码:最高位是符号位,0表示正数,1表示负数,其他位表示数值位

例如一个字节(8个二进制位)整数25

25的原码:0001 1001-25的原码:1001 1001

反码:正数的反码与原码一致,负数的反码是原码的符号位不变,其他位取反

25的反码: 0001 1001-25的反码:1110 0110

补码:正数的补码与原码一致,负数的补码等于反码基础上加1

25的补码:0001 1001-25的补码:1110 0111

正整数25在内存中的存储

使用计算器查看正整数十进制25在计算机底层的存储

① 切换到程序员

② 切换到一个字节

③ 输入正整数十进制25

④ 正整数十进制25二进制补码是0001 1001

负整数-25在内存中的存储

使用计算器查看负整数十进制-25在计算机底层的存储

① 切换到程序员

② 切换到一个字节

③ 输入负整数十进制-25

④ 负整数十进制-25二进制补码是1110 0111

Integer类提供静态方法public static String toBinaryString(int i)查看整数的二进制表示方式

1. 编辑IntegerTypeToBinary.java

package net.ittimeline.java.core.foundational.syntax.variable.type.primitive;/** * 正整数25和负整数-25在内存中的存储 * * @author tony 18601767221@163.com * @version 2024/10/15 9:19 * @since Java21 */public class IntegerTypeToBinary {    public static void main(String[] args) {        //Integer类提供静态方法public static String toBinaryString(int i)查看整数的二进制表示方式        System.out.println("正整数25的二进制补码方式是" + Integer.toBinaryString(25));        System.out.println("负整数-25的二进制补码方式是" + Integer.toBinaryString(-25));    }}

2. 运行IntegerTypeToBinary.java

程序运行结果

说明:负整数-25默认占据四个字节,因此Integer.toBinaryString(int i)方法输出的32位二进制位,从右往左截取8位二进制位的结果是1110 0111

1.4 整数类型溢出的内存原理

1. 编辑IntegerTypeOverFlow.java

package net.ittimeline.java.core.foundational.syntax.variable.type.primitive;/** * 整数类型溢出的内存原理 * * @author tony 18601767221@163.com * @version 2024/10/15 9:21 * @since Java21 */public class IntegerTypeOverFlow {    public static void main(String[] args) {        /*          计算机在执行运算的时候使用补码运算           1. byte的表示范围是-128 ~ +127           2. 135超过了byte的表示范围,在强制类型转换的时候会发生溢出           3. 135 默认的类型是int int在内存中占据4个字节 1Byte=8bit 4个字节对应32位           4. 135 在内存的二进制补码表示方式 0000 0000 0000 0000  0000 0000 1000 0111           5. 因为135强制类型转换成byte 因此会从右往左截取8位,结果是1000 0111           6. 1000 0111 占据1个字节,但是符号位(左边第一位)是1表示该数字是一个负数         当我们查看计算机执行结果的时候使用原码 将1000 0111转换原码            1. 根据补码得到反码:补码减1 1000 0111-1=1000 0110            2. 根据反码得到原码:最高位不变,其他位取反 1000 0110  也就是 1111 1001            3. 将原码1111 1001 转换成十进制-121            4. 因此最后的结果是-121         */        byte value = (byte) 135;        System.out.println("value = " + value);    }}

2. 运行IntegerTypeOverFlow.java

程序运行结果

说明:给整数变量赋值时如果超过数据类型的取值范围就会造成数据溢出

2 小数在内存中的存储2.1 float和double在内存中的存储格式

如果你明白了小数在内存中的存储形式,那么就能够知道以下问题的答案

为什么4个字节的float比8个字节的long存储数据范围大为什么8个字节的double比四个字节的float精度更高为什么float和double会有精度问题

由于浮点数的存储机制和整数存储不一样,Java的浮点类型遵守IEEE754标准,采用二进制的科学计数法表示浮点数。

对于float,第1位是符号位,接下来8位表示指数位,接下来23位表示尾数位

对于double,第1位是符号位,接下来11位表示指数位,接下来52位表示尾数位

符号位:0表示正数,1表示负数指数位:把十进制小数转换为二进制小数形式,小数点(左右)移动到其左边只保留一位有效数字,小数点移动的位数加上127,得到指数位值。(左移位数为正,右移位数为负数)尾数部分:小数点右侧的小数部分的二进制表示

2.2 小数3.625在内存中的存储2.3 小数0.9在内存中存储2.4 查看浮点数的二进制表示float的包装类Float提供了静态方法 public static int floatToIntBits(float value)查看float类型小数的二进制表示方式double的包装类Double提供了静态方法public static long doubleToLongBits(double value)查看double类型小数的二进制表示方式

1. 编辑FloatTypeToBits.java

package net.ittimeline.java.core.foundational.syntax.variable.type.primitive;/** * 查看浮点数的二进制表示 * * @author tony 18601767221@163.com * @version 2024/10/15 9:30 * @since Java21 */public class FloatTypeToBits {    public static void main(String[] args) {        System.out.println("1.查看四个字节浮点数3.625和0.9的二进制表示");        float firstFloatValue = 3.625f;        System.out.println("四个字节的浮点数3.625的二进制表示是"                + Integer.toBinaryString(Float.floatToIntBits(firstFloatValue)));        float secondFloatValue = 0.9f;        System.out.println("四个字节的浮点数0.9的二进制表示是"                + Integer.toBinaryString(Float.floatToIntBits(secondFloatValue)));        System.out.println("2.查看八个字节浮点数3.625和0.9的二进制表示");        double firstDoubleValue = 3.625;        System.out.println("八个字节的浮点数3.625的二进制表示是"                + Long.toBinaryString(Double.doubleToLongBits(firstDoubleValue)));        double secondDoubleValue = 0.9;        System.out.println("八个字节的浮点数0.9的二进制表示是"                + Long.toBinaryString(Double.doubleToLongBits(secondDoubleValue)));    }}

2. 运行FloatTypeToBits.java

程序运行结果

3 字符在内存中的存储3.1 ASCII字符编码字符在内存中存储

ASCII字符集使用ASCII字符编码存储字符,使用一个字节存储字符,ASCII字符编码二进制左边第一位是0

ASCII字符

码点(编号)

存储格式(二进制)

'a'

97

0110 0001

'A'

65

0100 0001

'0'

48

0011 0000

' '

32

0001 0000

'\n'

10

0000 1010

'\t'

9

0000 1001

1. 编辑ASCIICharacterToBinary.java

package net.ittimeline.java.core.foundational.syntax.variable.type.primitive;import java.nio.charset.Charset;/** * ASCII字符编码字符在内存中存储 * * @author tony 18601767221@163.com * @version 2024/10/15 9:35 * @since Java21 */public class ASCIICharacterToBinary {    public static void main(String[] args) {        //Charset.defaultCharset()用于获取当前JVM使用的编码        //UTF-8编码兼容ASCII        System.out.println("当前JVM使用的编码是" + Charset.defaultCharset());        /**********************ASCII字符集常用字符的编码**********************/        char lowercaseLetterA = 'a';        //(int) lowercaseLetterA 表示将字符类型转换为int类型,这样就可以获取字符对应的编码        System.out.println("字符" + lowercaseLetterA + "对应的编码是 " + (int) lowercaseLetterA                + " 二进制存储形式是" + Integer.toBinaryString(lowercaseLetterA));        char uppercaseLetterA = 'A';        //(int) uppercaseLetterA 表示将字符类型转换为int类型,这样就可以获取字符对应的编码        System.out.println("字符" + uppercaseLetterA + "对应的编码是 " + (int) uppercaseLetterA                + " 二进制存储形式是" + Integer.toBinaryString(uppercaseLetterA));        char zero = '0';        //(int) zero 表示将字符类型转换为int类型,这样就可以获取字符对应的编码        System.out.println("字符" + zero + "对应的编码是 " + (int) zero                + " 二进制存储形式是" + Integer.toBinaryString(zero));        char space = ' ';        //(int) space  表示将字符类型转换为int类型,这样就可以获取字符对应的编码        System.out.println("字符" + space + "对应的编码是 " + (int) space +                " 二进制存储形式是" + Integer.toBinaryString(space));        //\n表示换行转义字符        char newLine = '\n';        // (int) newLine  表示将字符类型转换为int类型,这样就可以获取字符对应的编码        System.out.println("字符'换行符'对应的编码是 " + (int) newLine +                " 二进制存储形式是" + Integer.toBinaryString(newLine));        //\t表示tab转义字符        char tab = '\t';        // (int) tab  表示将字符类型转换为int类型,这样就可以获取字符对应的编码        System.out.println("字符'制表符'对应的编码是 " + (int) tab +                " 二进制存储形式是" + Integer.toBinaryString(tab));    }}

2. 运行ASCIICharacterToBinary.java

程序运行结果

说明:Integer.toBinaryString(int i)查看整数二进制补码,如果整数是正整数时会省略二进制前面若干个0

3.2 UTF-8字符编码在内存中存储

Unicode字符集也称为统一码、标准万国码,是国际组织制定的,可以容纳世界上所有文字、符号的集合。

Unicode字符集的广泛应用促进了跨语言跨平台文本信息的无缝交换,使得在互联网和全球化软件开发中,不同语言的文字能够共存并正确显示。

Unicode字符集有三种编码方案,UTF-8、UTF-16和UTF-32,最为常用的UTF-8字符编码

UTF-8编码,可以用来表示Unicode标准中任何字符,它是电子邮件、网页及其他存储或传送文字的应用中优先采用的编码。互联网工程工作小组(IETF)要求所有互联网协议都必须支持UTF-8编码,所以我们开发Web应用也要使用UTF-8编码。

它使用一至四个字节(可变长度)为每个字符编码,编码规则如下:

128个US-ASCII字符,只需一个字节编码,兼容ASCII编码拉丁文、希腊文、阿拉伯文等字符,需要两个字节编码大部分常用字(中文、俄文、韩文、日文)使用三个字节编码。其他极少使用的Unicode辅助字符,使用四个字节编码

UTF-8还规定Unicode字符集对应的二进制存储方式

字节数

二进制存储方式

说明

1个字节

0xxx xxxx (ASCII码)

第一个字节开头必须是0

2个字节

110xxxx 10xxxxxx

第一个字节开头必须是110,第二个字节开头必须是10

3个字节

1110xxxx 10xxxxxx 10xxxxxx

第一个字节开头必须是1110,第二个、第三个字节开头必须是10

4个字节

11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

第一个字节开头必须是11110,第二个、第三个、第四个字节开头必须是10

UTF-8编码存储m我a

字符

UTF-8码值(字符编号)

二进制

UTF-8编码存储格式

m

109

0110 1101

0110 1101

25105

110 001000 010001

11100110 10001000 10010001

a

97

0110 0001

0110 0001

1. 编辑UnicodeCharacterToBinary.java

package net.ittimeline.java.core.foundational.syntax.variable.type.primitive;import java.nio.charset.Charset;/** * UTF-8字符编码在内存中存储 * * @author tony 18601767221@163.com * @version 2024/10/15 9:36 * @since Java21 */public class UnicodeCharacterToBinary {    public static void main(String[] args) {        //Charset.defaultCharset()用于获取当前JVM使用的编码        //UTF-8编码兼容ASCII        System.out.println("当前JVM使用的编码是" + Charset.defaultCharset());        String str = "m我a";        //使用平台默认的字符编码将字符串编码为一系列字节,即使用UTF-8编码的方式将字符串转为字节数组        byte[] bytes = str.getBytes();        //遍历字节数组,获取每个字节        for (int i = 0; i < bytes.length; i++) {            System.out.printf("第%d个字节内容是%d\n", i + 1, bytes[i]);        }        /*            第1个字节内容是109            第2个字节内容是-26            第3个字节内容是-120            第4个字节内容是-111            第5个字节内容是97         */        /*            109, -26, -120, -111, 97是怎么来的?            UTF-8编码下英文字母占据1个字节,109是字符m在内存存储的十进制表示方式, 97是字符a在内存存储的十进制表示方式            UTF-8编码下中文占据3个字节,-26, -120, -111是字符我在内存存储的十进制表示方式         */        //(int) 'm' 表示将字符字面量m转换为int类型,其目的就是获取m对应的编码109        System.out.println("字符m对应的编码是 " + (int) 'm');        //(int) 'a' 表示将字符字面量a转换为int类型,其目的就是获取a对应的编码97        System.out.println("字符a对应的编码是 " + (int) 'a');        //(int) '我' 表示将字符字面量a转换为int类型,其目的就是获取a对应的编码25105        System.out.println("字符我对应的编码是 " + (int) '我');        // 获取字符我对应编码的二进制表示方式是110001000010001        System.out.println("字符我对应的编码二进制表示方式是 " + Integer.toBinaryString('我'));        /*            一个字节表示八个二进制位            UTF-8编码规定 第一个字节开头必须是1110,第二个、第三个字节开头必须是10            字符我对应编码的二进制表示方式是110 001000 010001            因此第一个字节是1110 0110               第二个字节是1000 1000               第三个字节是1001 0001            数据的存储、计算都是补码,数据的打印输出是原码            第一个字节1110 0110 转换为原码并转换成十进制            补码:1110 0110            反码:1110 0101            原码:1001 1010            001 1010转换为十进制结果是-26            第二个字节是1000 1000转换为原码并转换成十进制            补码:1000 1000            反码:1000 0111            原码:1111 1000            1111 1000转换为十进制的结果是-120            第三个字节是1001 0001转换为原码并转换成十进制            补码:1001 0001            反码:1001 0000            原码:1110 1111            1110 1111转换为十进制的结果是-111         */    }}

2. 运行UnicodeCharacterToBinary.java

程序运行结果

标签: #内存中什么可以储存0或10 #内存用于存储 #内存中什么可以存储0或1 #内存如何存储0和1