【问题标题】:Strange Java Behavior [closed]奇怪的 Java 行为
【发布时间】:2022-01-13 17:05:49
【问题描述】:

首先,这个问题的出现是因为我试图让一个 hello world 程序(第一个 main 方法被注释掉)尽可能地复杂。我尝试重写其中一些以使其更具可读性,但保持我正在解决的奇怪行为。

具体来说,在 for 循环中,我尝试将字符串转换为浮点数,然后将浮点数截断为 ASCII 值,最后截断为表示“Hello, World!”的字符。问题是,在条件内部,在 for 循环中,如果你只是简单地使用 (i == 0),它会将 h 大写就可以了,但是当你添加
(i == 6) 它的行为非常奇怪,最终打印出不一致的字符,例如“Hello,d!”、“Hello,!”和“你好,rld!” (除其他外)。谁能向我解释这种行为?谢谢。

import java.util.Scanner;

class helloWorld {

    // public static void main(String[] args) {
    // System.out.println("Hello, World!");
    // }

    public static void main(String[] args) {
        //This array is just soon to be truncated ASCII vals
        String[] nums = {"104.367", "101.432", "108.43276", "108.1", "111.43", "44.231", "32.12", "119.32", "111.24", "114.37", "108.2", "100.52", "33.237", "10.4"};
        
        //Empty "Hello, World!" string
        String message = "";

        //This is to store the converted ASCII values
        char[] chars = new char[nums.length];

        //this is just the difference in ASCII vals to go from lower to uppercase letters
        int toUpperCase = 32;

        for (int i = 0; i < nums.length; i++){
            //i == 6 || i == 0 because I want the w and h to be capitalized
            //i == 0 capitalizes the 'h' and prints as expected but adding "i == 6 ||" to the condition causes it to break and print chars inconsistently
            if (i == 6 || i == 0) {
                //converts from float to int (truncates decimals to the normal ASCII val) and then from the ASCII value to the char
                chars[i] = (char)((int)((Float.parseFloat(nums[i])) - toUpperCase));
            } else {
                chars[i] = (char)((int)(Float.parseFloat(nums[i])));
            }
            System.out.print(chars[i]);
        }

        System.out.print(message);
        }
}

【问题讨论】:

  • i == 6 是空格,而不是 W。请改用7。
  • nums[6] 是“32.12”,所以你基本上是在打印 U+0000。我不知道我希望控制台对此做什么。
  • 你从空间中减去 32。该代码按设计工作正常,并且无法打印您所说的任何内容,除非从空格中减去 32 生成的怪异控制字符会导致奇怪。使 i ==7 并打印 Hello, World! - 每次。
  • 这可能只是一个错字,OP 意味着将w 大写,它位于索引7 而不是6。所以i == 7 它可以工作。由于打字错误,投票结束。
  • @rzwitserloot 实际上是空间。恰好有一个 ASCII 值 32。减去32 得到0,导致空字符。

标签: java obfuscation


【解决方案1】:

tl;博士

这个错误实际上是一个小错误,你使用了i == 6,但你应该使用i == 7。


索引

让我们分解发生了什么以及为什么。首先,您正在读取的源字符串(即使您使用floats,但没关系)是Hello, World!,您的数组的索引如下:

// _ denotes the space
h e l l o , _ w o r  l  d  !
0 1 2 3 4 5 6 7 8 9 10 11 12

请注意,6 实际上是空间 的索引,而不是您想要大写的w。


NUL 字符

接下来,从空格的 ASCII 值中减去 32。有趣的是,它的 ASCII 值也是 32:

System.out.println((int) ' '); // 32

所以你的减法结果是0。 ASCII 值为0 的char 就是所谓的null character(不要与Java 关键字null 混淆),它是一个没有视觉表示的特殊控制字符。也可以写成'\0'。

System.out.println((char) 0);

所以当你告诉你的控制台打印空字符时,它可能会开始做一些有趣的事情。虽然,我测试的控制台只是简单地跳过字符并始终打印Hello,world!。

如果你想用一个最小的例子来试试,使用这个:

System.out.println("Hello,\0world!");

这是您的代码生成的字符串。


ASCII 表

此时,这里是带有 null 字符和 空格 突出显示的 ASCII 表(来自 Wikipedia):

您还可以看到,前 32 个字符都是控制字符,没有直接的视觉表示。事实上,试试这个:

System.out.print((char) 7);

根据您的控制台,您现在可能会听到哔声。

【讨论】:

  • 感谢您抽出宝贵时间撰写本文!我什至没有意识到我正在打印 NUL 字符,所以我真的不知道发生了什么。我今天学到了一些新东西。
猜你喜欢
  • 2023-04-06
  • 2018-08-15
  • 2017-09-27
  • 2015-12-04
  • 2012-02-16
  • 2021-09-28
  • 2023-03-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多