在Java中,两个字符相加的结果是int还是char?
Posted
技术标签:
【中文标题】在Java中,两个字符相加的结果是int还是char?【英文标题】:In Java, is the result of the addition of two chars an int or a char? 【发布时间】:2012-01-31 02:23:35 【问题描述】:当添加 'a' + 'b'
时,它会生成 195。输出数据类型是 char
还是 int
?
【问题讨论】:
如果类型是char
,那么'a' + 'b'
的值就不是195
而是'Ã'
这里是 195 - ideone.com 但在 Eclipse 中没有。
你从算法书里读到了,哈哈!我正是因为这个练习才来到这里的;)
Java (OpenJDK 8) – Try It Online
【参考方案1】:
char
和 byte
(和 short
)上的二进制算术运算升级为 int
-- JLS 5.6.2。
【讨论】:
和一元算术运算。【参考方案2】:根据binary promotion rules,如果两个操作数都不是double、float 或long,则都提升为int。但是,我强烈建议不要将 char 类型视为数字,这会违背其目的。
【讨论】:
将char
用作数值完全在其目的之内,这就是JLS 在这种用法上花费如此之多的原因。【参考方案3】:
添加 Java 字符、短裤或字节的结果是 int:
Java Language Specification on Binary Numeric Promotion:
如果任何操作数属于引用类型,则取消装箱转换 (§5.1.8)执行。然后: 如果任一操作数是双精度类型,则 其他转换为双精度。 否则,如果任一操作数属于类型 浮动,另一个转换为浮动。 否则,如果任一操作数 是 long 类型,另一个转换为 long。 否则,两者都 操作数被转换为 int 类型。
But note what it says about compound assignment operators (like +=):
将二元运算的结果转换为左侧变量的类型……并将转换结果存入变量中。
例如:
char x = 1, y = 2;
x = x + y; // compile error: "possible loss of precision (found int, required char)"
x = (char)(x + y); // explicit cast back to char; OK
x += y; // compound operation-assignment; also OK
一般来说,找出结果类型的一种方法是将其转换为 Object 并询问它是什么类:
System.out.println(((Object)('a' + 'b')).getClass());
// outputs: class java.lang.Integer
如果您对性能感兴趣,请注意Java bytecode 甚至没有专门用于较小数据类型的算术指令。例如,对于加法,有指令iadd
(用于整数)、ladd
(用于长整数)、fadd
(用于浮点数)、dadd
(用于双精度数),仅此而已。为了用较小的类型模拟x += y
,编译器将使用iadd
,然后使用i2c
(“int to char”)之类的指令将int的高字节归零。如果本机 CPU 具有针对 1 字节或 2 字节数据的专用指令,则由 Java 虚拟机在运行时对其进行优化。
如果您想将字符连接为字符串而不是将它们解释为数字类型,有很多方法可以做到这一点。最简单的方法是在表达式中添加一个空字符串,因为添加一个字符和一个字符串会产生一个字符串。所有这些表达式都会产生字符串"ab"
:
'a' + "" + 'b'
"" + 'a' + 'b'
(这是因为"" + 'a'
首先被评估;如果""
在最后,你会得到"195"
)
new String(new char[] 'a', 'b' )
new StringBuilder().append('a').append('b').toString()
String.format("%c%c", 'a', 'b')
【讨论】:
【参考方案4】:你不妨学习以下关于char
的表达方式。
char c='A';
int i=c+1;
System.out.println("i = "+i);
这在 Java 中完全有效,并返回 66
,即 c+1
字符 (Unicode) 的对应值。
String temp="";
temp+=c;
System.out.println("temp = "+temp);
这在 Java 中太有效了,String 类型变量 temp
自动接受 char 类型的 c
并在控制台上生成 temp=A
。
以下所有语句在 Java 中同样有效!
Integer intType=new Integer(c);
System.out.println("intType = "+intType);
Double doubleType=new Double(c);
System.out.println("doubleType = "+doubleType);
Float floatType=new Float(c);
System.out.println("floatType = "+floatType);
BigDecimal decimalType=new BigDecimal(c);
System.out.println("decimalType = "+decimalType);
Long longType=new Long(c);
System.out.println("longType = "+longType);
虽然c
是char
的一种类型,但可以在各自的构造函数中正确地提供它,并且所有上述语句都被视为有效语句。它们分别产生以下输出。
intType = 65
doubleType = 65.0
floatType = 65.0
decimalType = 65
longType =65
char
是原始数字整数类型,因此受制于这些野兽的所有规则,包括转换和提升。你会想要阅读这个,JLS 是最好的来源之一:Conversions and Promotions。尤其是阅读“5.1.2 扩展原语转换”的简短部分。
【讨论】:
【参考方案5】:Java 编译器可以将其解释为任一。
通过编写程序并查找编译器错误来检查它:
public static void main(String[] args)
int result1 = 'a' + 'b';
char result2 = 'a' + 'b';
如果它是一个字符,那么第一行会给我一个错误,而第二行不会。 如果是 int,则相反。
我编译了它,我得到了.....没有错误。 所以 Java 两者都接受。
但是,当我打印它们时,我得到了:
整数:195
字符:Ã
当你这样做时会发生什么:
char result2 = 'a' + 'b'
执行隐式转换(从 int 到 char 的“原始缩小转换”)。
【讨论】:
我很惊讶您在第二种情况下没有收到编译器警告,因为缩小可能会导致精度损失。 @eboix: 你写了 "编译器自动转换为 char 或 int" [原文如此]...这是不正确的,因为 int 不是“强制转换”到 int 并且从 int 到 char 不是“强制转换”而是“缩小原始转换" ; ) 是的。我也是这么期待的。在制作程序之前,我实际上已经写了部分答案,但是当我看到我没有收到任何警告或错误时,我就删除了它。 @eboix: eh eh :) 我会编辑它,但我还没有 2000 个声望点,因此我的评论而不是编辑; ) 如果你愿意,@user988052,我可以把它改回原来的样子,你可以编辑它,获得积分。如果您的声望点少于 2000,您仍然可以对其进行编辑。唯一的问题是发帖的人必须接受编辑。我现在就把它改回来,这样你就可以得到本应属于你的两点。【参考方案6】:虽然您已经有了正确的答案(在 JLS 中引用),但这里有一些代码可以验证您在添加两个 char
s 时是否获得了 int
。
public class CharAdditionTest
public static void main(String args[])
char a = 'a';
char b = 'b';
Object obj = a + b;
System.out.println(obj.getClass().getName());
输出是
java.lang.Integer
【讨论】:
这不是一个令人信服的验证,因为您已经将拳击转换加入其中。int
和 Integer
类型不是一回事。更有说服力的验证是尝试将a + b
分配给int
变量或char
变量。后者给出了一个编译错误,实际上是“你不能将int
分配给char
”。【参考方案7】:
char
表示为 Unicode
值,其中 Unicode 值由 \u
后跟 Hexadecimal
值表示。
由于对 char
值的任何算术运算提升为 int
,所以 'a' + 'b'
的结果计算为
1.) 使用Unicode Table
将Unicode
值应用于对应的char
2.) 应用Hexadecimal to Decimal 转换,然后对Decimal
值执行操作。
char Unicode Decimal
a 0061 97
b 0062 98 +
195
Unicode To Decimal Converter
例子
0061
(0*163) + (0*162) + (6*161) + (1*160)
(0*4096) + (0*256) + (6*16) + (1*1)
0 + 0 + 96 + 1 = 97
0062
(0*163) + (0*162) + (6*161) + (2*160)
(0*4096) + (0*256) + (6*16) + (2*1)
0 + 0 + 96 + 2 = 98
因此97 + 98 = 195
示例 2
char Unicode Decimal
Ջ 054b 1355
À 00c0 192
--------
1547 +
1163 -
7 /
260160 *
11 %
【讨论】:
这不是问题要问的。 仅供参考,我对上述评论的详细回复已被模组删除,这解释了我从已删除帖子中迁移答案的原因。如果我的回复已被删除以掩盖 SO 审核的缺陷,那么您至少可以删除上述评论或以某种方式指示观众,这样我就不必再写一条评论了? SO mods的问题 我支持我的评论。正如我回复您...但随后删除...您在此处发布此问题的原因并没有改变这样一个事实,即该问题 95% 偏离主题,5% 重复先前的答案。如果你想保存你浪费的努力的结果,把它保存在你的硬盘上会更合适。或者找到其他相关的问题。 如果您对版主有意见,请访问 meta.***.com。并提供证据。我在这里要做的就是整理>>this 我理解你的观点,但无法理解忽略 Unicode 转换细节的事实,作为一个附加值,它可能会帮助一些读者,所以我想保留这个答案(我知道它是对你没用,而且似乎离题了)。我避免使用元和类似的地方,因为在没有权力或支持的情况下做这些事情并不容易,这需要大量的时间和精力。我更喜欢保持内心的平静,陛下。【参考方案8】:虽然Boann's answer 是正确的,但是当常量表达式出现在赋值上下文中时,会出现复杂情况。
考虑以下示例:
char x = 'a' + 'b'; // OK
char y = 'a';
char z = y + 'b'; // Compilation error
发生了什么事?他们的意思是一样的,不是吗?为什么在第一个示例中将int
分配给char
是合法的?
当常量表达式出现在赋值上下文中时,Java 编译器会计算表达式的值并查看它是否在您要赋值的类型范围内。如果是,则应用隐式缩小原语转换。
在第一个例子中,'a' + 'b'
是一个常量表达式,它的
值将适合char
,因此编译器允许将int
表达式结果隐式缩小为char
。
在第二个示例中,y
是一个变量,因此 y + 'b'
不是
常量表达式。所以即使Blind Freddy 可以看到
值将适合,编译器不允许任何隐式缩小,并且您会收到一个编译错误,指出无法将 int
分配给 char
。
关于在这种情况下何时允许隐式缩小原语转换,还有一些其他注意事项;有关详细信息,请参阅 JLS 5.2 和 JLS 15.28。
后者详细解释了常量表达式的要求。可能不是你想的那样。 (例如,仅将 y
声明为 final
没有帮助。)
【讨论】:
以上是关于在Java中,两个字符相加的结果是int还是char?的主要内容,如果未能解决你的问题,请参考以下文章