当前位置: 首页 > 面试题库 >

为什么'(int)(char)(byte)-2'在Java中产生65534?

陆城
2023-03-14
问题内容

我在工作的技术测试中遇到了这个问题。给出以下代码示例:

public class Manager {
    public static void main (String args[]) {
        System.out.println((int) (char) (byte) -2);
    }
}

输出为65534。

此行为仅显示负值。0和正数产生相同的值,表示在SOP中输入的那个。此处的字节无关紧要;我尝试过没有它。

所以我的问题是:这到底是怎么回事?


问题答案:

在您了解这里发生的事情之前,我们需要达成一些先决条件。了解以下要点后,剩下的就是简单的推论:

  1. JVM中的所有原始类型都表示为一系列位。的int类型是由32位,所表示charshort类型由16位和byte类型由8位表示。

  2. 所有JVM号都是带符号的,其中char类型是唯一的无符号“数字”。对数字进行签名时, 最高 位用于表示该数字的符号。对于此最高位,0代表一个非负数(正数或零),1代表一个负数。同样,对于带正负号的数字,负值将被 反转 为正数的递增顺序(技术上称为二进制补码表示法)。例如,正值byte以位表示,如下所示:

    00 00 00 00 => (byte) 0
    

    00 00 00 01 => (byte) 1
    00 00 00 10 => (byte) 2

    01 11 11 11 => (byte) Byte.MAX_VALUE


负数的位顺序相反:

    11 11 11 11 => (byte) -1
11 11 11 10 => (byte) -2
11 11 11 01 => (byte) -3
...
10 00 00 00 => (byte) Byte.MIN_VALUE

这种反向表示法还解释了为什么负范围可以容纳一个额外的数字,而正范围包括其中的数字表示0。请记住,所有这些仅是 解释
模式的问题。您可以以不同的方式记下负数,但是负数的这种反转表示法非常方便,因为它允许进行一些相当快速的转换,我们稍后将在一个小示例中看到。

如前所述,这不适用于该char类型。该char类型表示Unicode字符,其非负“数值范围”为0to
65535。每个数字都引用一个16位Unicode值。

  1. 当之间进行转换intbyteshortcharboolean类型的JVM需要添加或截比特。

如果目标类型由比其转换的类型更多的位来表示,那么JVM会简单地用给定值的最高位(代表签名)的值来填充其他插槽:

    |     short   |     byte    |
|             | 00 00 00 01 | => (byte) 1
| 00 00 00 00 | 00 00 00 01 | => (short) 1

得益于倒数符号,该策略也适用于负数:

    |     short   |     byte    |
|             | 11 11 11 11 | => (byte) -1
| 11 11 11 11 | 11 11 11 11 | => (short) -1

这样,将保留值的符号。在不赘述为JVM实现此操作的细节的情况下,请注意,此模型允许通过便宜的shift操作执行转换,这显然是有利的。

如前所述,该规则的一个例外是 扩展 了一个char无符号类型。由于我们说没有符号,因此也不需要反转符号,因此总是通过用填充附加位来应用
a进行的转换。的A转换到因此被执行为:char``0``char``int

    |            int            |    char     |     byte    |
|                           | 11 11 11 11 | 11 11 11 11 | => (char) \uFFFF
| 00 00 00 00 | 00 00 00 00 | 11 11 11 11 | 11 11 11 11 | => (int) 65535

当原始类型的位数多于目标类型的位数时,仅会切断附加位。只要原始值适合目标值,就可以正常工作,例如short将a 转换为a的情况如下byte

    |     short   |     byte    |
| 00 00 00 00 | 00 00 00 01 | => (short) 1
|             | 00 00 00 01 | => (byte) 1
| 11 11 11 11 | 11 11 11 11 | => (short) -1
|             | 11 11 11 11 | => (byte) -1

但是,如果值 太大太小 ,将不再起作用:

    |     short   |     byte    |
| 00 00 00 01 | 00 00 00 01 | => (short) 257
|             | 00 00 00 01 | => (byte) 1
| 11 11 11 11 | 00 00 00 00 | => (short) -32512
|             | 00 00 00 00 | => (byte) 0

这就是为什么缩小铸件有时会导致奇怪的结果的原因。您可能想知道为什么以这种方式实现缩小。您可能会争辩说,如果JVM检查一个数字的范围,而是将一个不兼容的数字转换为相同符号的最大可表示值,它将更加直观。但是,这将需要分支,这是一项昂贵的操作。这一点特别重要,因为这两个的补码表示法允许廉价的算术运算。

有了所有这些信息,我们可以看到-2您的示例中的数字发生了什么:

|           int           |    char     |     byte    |
| 11 11 11 11 11 11 11 11 | 11 11 11 11 | 11 11 11 10 | => (int) -2
|                         |             | 11 11 11 10 | => (byte) -2
|                         | 11 11 11 11 | 11 11 11 10 | => (char) \uFFFE
| 00 00 00 00 00 00 00 00 | 11 11 11 11 | 11 11 11 10 | => (int) 65534

如您所见,byte强制转换是多余的,因为对的强制转换char会削减相同的位。

如果您更喜欢所有这些规则的正式定义,那么JVMS也可以指定所有这些。

最后一点:类型的位大小不一定代表JVM为在其内存中表示该类型而保留的位数。作为事实上,在JVM不区分之间booleanbyteshortcharint类型。它们全部由相同的JVM类型表示,其中虚拟机仅模拟这些转换。在方法的操作数堆栈(即方法中的任何变量)上,所有已命名类型的值都占用32位。但是,对于任何JVM实现者都可以随意处理的数组和对象字段,情况并非如此。



 类似资料:
  • 问题内容: 所以我正在学习Java,但是我有一个问题。看来,类型,并且将是只是我会永远需要的变量方面的一切,也许除外好时,需要在多个十进制数字都可以使用。 我的问题是,其他类型的如,,,等曾经在正常的日常编程中使用?这些可以用于哪些实际用途?它们的作用是什么? 问题答案: 除了“ short”(可能是对空间的浪费)之外,“ short”可能是一个例外-有时候,从字面上看,它们都是上课的动力: 当您

  • 问题内容: 我生成了一个安全的随机数,并将其值放入一个字节中。这是我的代码。 但是我遇到一个错误: 问题答案: 您的数组是基元,但是您正在尝试对其调用方法。 您无需做任何显式操作即可将a转换为,只需: …因为这不是垂头丧气。 请注意,-to- 转换的默认行为是保留值的符号(请记住,在Java中是带符号的类型)。因此,例如: 如果您想到的是无符号(156)而不是有符号(-100),那么从Java 8

  • 问题内容: 下面是一个代码片段, 但是我得到的是空输出。 我将得到1作为输出。 有人可以解释吗?如果我想像第一个代码片段一样将int转换为char,该怎么办? 问题答案: 会打印出ascii值为1的字符(首字符,这是不可打印的)。 将以ascii值49输出一个字符(一个对应于“ 1”) 如果要转换数字(0-9),则可以将数字加48并进行转换,例如;。 如果要转换 as asi的ascii值,可以使

  • 下面是一段代码片段, 但我得到的是空输出。 我将得到1作为输出。 有人能解释一下吗?如果我想像第一个代码片段那样将int转换成char,我应该怎么做?

  • 问题内容: AsicII表:http://www.asciitable.com 下面的代码打印出相应字符的Dec值,例如“ 123”-> 49 50 51 但是我注意到java是一种强类型语言,这意味着必须在编译时进行所有转换,但是代码如何知道如何以及何时将char转换为AsicII表中正确的Dec值呢?我弄乱了任何Java /编程基础知识吗? 问题答案: A 只是一个无符号的16位数字,因此,由

  • 示例:类中的字段使用。 如果差异太小,那么为什么这些数据类型(、)会存在呢?