为什么Java八进制转义只能达到255?

Java语言规范声明字符串内的转义是“正常”C类,如\n\t ,但它们也指定从\0\377八进制转义。 具体来说,JLS声明:

 OctalEscape: \ OctalDigit \ OctalDigit OctalDigit \ ZeroToThree OctalDigit OctalDigit OctalDigit: one of 0 1 2 3 4 5 6 7 ZeroToThree: one of 0 1 2 3 

意味着像\4715这样的东西是非法的,尽管它在Java字符的范围内(因为Java字符不是字节)。

为什么Java有这种任意限制? 你是如何指定超过255的字符的八进制代码?

由于纯粹的历史原因,Java可能完全支持八进制转义序列。 这些逃逸序列起源于C(或者可能是C的前辈B和BCPL),在像PDP-7这样的计算机统治地球的日子里,大量编程是在assembly中或直接在机器代码中完成的,并且八进制是首选的数字用于编写指令代码的基础,并且没有Unicode,只有ASCII,因此三个八进制数字足以表示整个字符集。

当Unicode和Java出现时,八进制几乎已经让hex成为十进制时的首选数字基数。 所以Java的\u转义序列采用hex数字。 可能只支持八进制转义序列以使C程序员感到舒服,并且可以很容易地将字符串常量从C程序复制到Java程序中。

查看这些链接了解历史琐事:

http://en.wikipedia.org/wiki/Octal#In_computers
http://en.wikipedia.org/wiki/PDP-11_architecture#Memory_management

对“为什么”这个问题的真正答案需要我们向Java语言设计师提问。 我们无法做到这一点,我怀疑他们甚至可以回答这个问题。 ( 还记得你20年前的详细技术讨论吗?)

然而,对这种“限制”的合理解释是:

  • 八进制转义是从C / C ++中借来的,其中它们也被限制为8位,
  • 八进制是老式的,IT人们通常更喜欢并且更喜欢hex,而且
  • Java支持表达Unicode的方式,可以通过直接将其嵌入源代码中,也可以使用\u Unicode转义符…不限于字符串和字符文字。

说实话,我从来没有听过任何人(除了你)认为八进制文字在Java中应该长于8位。


顺便说一句,当我开始计算字符集时,往往是硬件特定的,并且通常少于 8位。 在我的本科课程和gradle后的第一份工作中,我使用了具有60位字和6位字符集的CDC 6000系列机器 – “显示代码”我认为我们称之为。 Octal在这种情况下非常好用。 但随着行业向(几乎)普遍采用8/16/32/64位架构迈进,人们越来越多地使用hex而不是八进制。

如果我能理解规则(如果我错了请纠正我):

 \ OctalDigit Examples: \0, \1, \2, \3, \4, \5, \6, \7 \ OctalDigit OctalDigit Examples: \00, \07, \17, \27, \37, \47, \57, \67, \77 \ ZeroToThree OctalDigit OctalDigit Examples: \000, \177, \277, \367,\377 

\t\n\\不属于OctalEscape规则; 它们必须遵循单独的转义字符规则。

十进制255等于八进制377(在科学模式下使用Windows计算器确认)

因此,三位八进制值落在\000 (0)到\377 (255)的范围内

因此, \4715不是有效的八进制值,因为它超过三个八位数的规则。 如果要访问具有十进制值4715的代码点字符,请使用Unicode转义符号\u来表示UTF-16字符\u126B (十进制forms为4715),因为每个Java char都是Unicode UTF-16。

来自http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/Character.html :

char数据类型(以及Character对象封装的值)基于原始Unicode规范,该规范将字符定义为固定宽度的16位实体。 此后,Unicode标准已更改为允许表示forms需要16位以上的字符。 合法代码点的范围现在是U + 0000到U + 10FFFF,称为Unicode标量值。 (请参阅Unicode标准中U + n表示法的定义。)

从U + 0000到U + FFFF的字符集有时被称为基本多语言平面(BMP)。 代码点大于U + FFFF的字符称为增补字符。 Java 2平台在char数组和String和StringBuffer类中使用UTF-16表示。 在此表示中,补充字符表示为一对char值,第一个来自高代理范围(\ uD800- \ uDBFF),第二个来自低代理范围(\ uDC00- \ uDFFF)。

编辑:

超出8位范围(大于一个字节)的有效八进制值的任何内容都是特定于语言的。 一些编程语言可以继续匹配Unicode实现; 有些可能不会(将其限制为一个字节)。 Java肯定不允许它,即使它有Unicode支持。

一些编程语言(依赖于供应商)限制为单字节八进制文字

  1. Java(所有供应商): – 一个八进制整数常量,以0或单个数字开头,基数为8(最高为0377); \ 0到\ 7,\ 00到\ 77,\ 000到\ 377(以八进制字符串文字格式)
  2. C / C ++(Microsoft) – 一个八进制整数常量,以0开头(最多0377); 八进制字符串文字格式\nnn
  3. Ruby – 一个八进制整数常量,以0开头(最多0377); 八进制字符串文字格式\nnn

一些编程语言(依赖于供应商)支持大于一字节的八进制文字

  1. Perl – 以0开头的八进制整数常量; 八进制字符串文字格式\nnn请参阅http://search.cpan.org/~jesse/perl-5.12.1/pod/perlrebackslash.pod#Octal_escapes

一些编程语言不支持八进制文字

  1. C# – 使用Convert.ToInt32(integer, 8)作为base-8 如何使用c#将二进制数转换为八进制数?

\ 0- \ 377八进制转义也是从Cinheritance的,并且该限制在C语言中具有相当大的意义,其中字符==字节(至少在wchar_t之前的平静天)。

我知道没有理由将八进制转义限制为0到255的unicode代码点。这可能是出于历史原因。 这个问题基本上没有答案,因为没有技术理由不在Java设计过程中增加八进制转义的范围。

但应该注意的是,unicode转义和八进制转义之间没有那么明显的区别。 八进制转义只作为字符串的一部分处理,而unicode转义可以出现在文件的任何位置,例如作为类名称的一部分。 另请注意,以下示例甚至不会编译:

 String a = "\u000A"; 

原因是,\ u000A在很早的阶段(基本上在加载文件时)扩展到换行符。 以下代码不会生成错误:

 String a = "\012"; 

编译器解析代码 ,\ 012被展开。 这也适用于其他转义,如\ n,\ r,\ t \ t等。

总而言之:unicode转义不是八进制转义的替代。 它们是完全不同的概念。 特别是,为了避免任何问题(如上面的\ u000A),应该对代码点0到255使用八进制转义,对于高于255的代码点使用unicode转义。