Java:减去';0';从char获取一个int。。。为什么这样做有效?

Java:减去';0';从char获取一个int。。。为什么这样做有效?,java,Java,这很好: int foo = bar.charAt(1) - '0'; 但这并不是,因为bar.charAt(x)返回一个char: int foo = bar.charAt(1); 似乎从字符中减去“0”就是将其强制转换为整数 为什么,或者如何,减去字符串“0”(或者它是一个字符?)会将另一个字符转换成整数?这是一个聪明的技巧。字符实际上与短裤的类型/长度相同。现在,当您有一个表示ASCII/unicode数字(如“1”)的字符,并从中减去最小的ASCII/unicode数字(如“0”),

这很好:

int foo = bar.charAt(1) - '0';
但这并不是,因为bar.charAt(x)返回一个char:

int foo = bar.charAt(1);
似乎从字符中减去“0”就是将其强制转换为整数


为什么,或者如何,减去字符串“0”(或者它是一个字符?)会将另一个字符转换成整数?

这是一个聪明的技巧。字符实际上与短裤的类型/长度相同。现在,当您有一个表示ASCII/unicode数字(如“1”)的字符,并从中减去最小的ASCII/unicode数字(如“0”),那么您将得到该数字的对应值(因此为1)


因为char与short相同(虽然是无符号的short),所以可以安全地将其转换为int。如果涉及算术运算,转换总是自动完成的,因为在Java中,如果不使用数字指定类型指示符,则它将采用整数。 我的意思是,如果你想设置一个长值,它需要是0L

对两个不同的数值执行数值运算,结果取较大值。因此,一个字符(一个数值)减去一个整数,就会得到一个整数

你会发现这同样有效

long val = bar.charAt(1) - 0L;

char
s隐式转换为
int

   public static void main(String [] args) throws Exception {
     String bar = "abc";
     int foo = bar.charAt(1) - '0';
     int foob = bar.charAt(1);
     System.err.println("foo = " + foo + "   foob = " + foob);
   }
输出:
foo=50 foob=98


也许你放了两个
int foo…
,这是因为它不起作用?

'0'
也是一个字符。事实证明,Java中的字符有一个unicode(UTF-16)值。使用带有字符的
-
运算符时,Java将使用整数值执行操作


例如,
intx='A'-'0';//x=17

您的第二次剪断应该可以正常工作,不过:

int foo = bar.charAt(1);
char
,就像
short
byte
一样,如果需要,将始终以静默方式转换为
int


这将很好地编译:
inti='c'

以下代码工作正常

int foo = bar.charAt(1);

与引用类型类似,任何Java原语都可以被分配,而不必强制转换到它被视为其子类型的另一个原语。原语的子类型规则由给出
char
被认为是
int
的一个子类型,因此任何
char
都可以分配给
int
这是一个古老的ASCII技巧,适用于从“0”开始依次排列数字“0”到“9”的任何编码。在Ascii中, “0”是值为0x30的字符,“9”是0x39。 基本上, 如果您有一个数字字符, 减去“0”将其“转换”为其数字值

我不同意@Lukas Eder的观点,认为这是一个可怕的把戏; 因为这一行动的意图是显而易见的 来自代码。 如果您使用的是Java,并且有一个
字符串
包含数字且您希望将所述
字符串
转换为
int
我建议你使用
Integer.parseInt(您的字符串)


这种技术的好处是对未来的维护程序员来说是显而易见的。

您的代码可以编译无误,运行时不会引发异常,但是在char和int之间转换是不好的做法。首先,它使代码变得混乱,导致以后的维护难题。其次,巧妙的“技巧”可以阻止编译器优化字节码。快速编写代码的最佳方法之一是编写哑的代码(即,不聪明的代码)。

我将重复@Mark Peters上面所说的,以防人们忽视他的评论

正如我引述: "
不要错误地认为“0”==0。实际上,“0”==48

@Lukas不会的,请看我的答案。不要错误地认为
'0'==0
。事实上,
'0'==48
。点击啊,现在它有了完美的意义!如果你把它作为一个答案,并告诉我这个隐式cast不会返回字符的十进制表示形式,就像@MarkPeters指出的那样,因此如果例如bar.charAt(1)返回'A',dec表示形式是65,int foo将是17,'A'-'0'=65-48=17,而不是65。Leetcode中的许多问题都使用了这个技巧,但是我没有看到有人问过这个技巧是如何解决Leetcode问题的。短裤可以有负值,char没有。也不是ASCII而是unicode(小但重要的区别):尝试
inty='\uffff'-'\ufffe'你是对的。对于数字,ASCII码和Unicode码恰好重合,这就是为什么我首先想到ASCII码,这很好。我确实需要马克·彼得的评论,让我意识到“对应值”的意思是我实际上从49-57减去了48。另外,我得到的错误实际上是一个数组越界异常,所以我的问题可能是误导性的,因为我说第一个示例“不起作用”。谢谢!:)需要明确的是,
char
在Java中不被视为
short
的子类型。。。你的回答听起来有点像
char
short
都是
int
的直接子类型。此外,无论是否涉及算术运算,在任何类型和被视为超类型的任何类型之间都会自动执行“强制转换”。它一点也不抱怨。您可以很好地执行
int y=s.charAt(1)
操作,没有编译或运行时错误(假设
s
有两个以上的字符)。我认为OP对为什么没有返回相同的结果感到困惑。@Bart:UTF-16是unicode的一种编码格式,但你是对的。@Mark:我知道,但对于unicode点65k以上的字符,(至少)使用了两个UTF-16字符。你选择了一个很好的例子来说明字符算术的有限用处。在上面的例子中,我得到了
jshell>intx='0'-'A'x=>-17
。不是说它是,只是你不需要显式地将
char
转换为
int
,所以不清楚为什么searbe需要减法。不,如果我是