添加'a' + 'b'
时会产生 195。输出数据类型是char
还是int
?
8 回答
添加 Java 字符、短裤或字节的结果是一个int:
- 如果任何操作数是引用类型,则执行拆箱转换(第 5.1.8 节)。然后:
- 如果任一操作数是 double 类型,则另一个操作数将转换为 double。
- 否则,如果任一操作数的类型为浮点型,则另一个将转换为浮点型。
- 否则,如果任一操作数是 long 类型,则另一个将转换为 long。
- 否则,两个操作数都转换为 int 类型。
二元运算的结果被转换为左侧变量的类型……并将转换结果存储到变量中。
例如:
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 字节码甚至没有专门用于较小数据类型的算术指令。例如,对于加法,有指令iadd
(对于整数)、ladd
(对于长整数)、 fadd
(对于浮点数)、dadd
(对于双精度数),仅此而已。为了模拟x += y
较小的类型,编译器将使用iadd
int 的高字节,然后使用类似i2c
(“int to char”)的指令将其归零。如果本机 CPU 具有针对 1 字节或 2 字节数据的专用指令,则由 Java 虚拟机在运行时对其进行优化。
如果您想将字符连接为字符串而不是将它们解释为数字类型,有很多方法可以做到这一点。最简单的方法是在表达式中添加一个空字符串,因为添加一个字符和一个字符串会产生一个字符串。所有这些表达式都会产生 String "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')
char
和byte
(and short
)上的二进制算术运算升级到int
- JLS 5.6.2。
您可能希望学习以下有关 的表达式char
。
char c='A';
int i=c+1;
System.out.println("i = "+i);
这在 Java 中完全有效,并返回66
. 的字符 (Unicode) 的对应值c+1
。
String temp="";
temp+=c;
System.out.println("temp = "+temp);
这在 Java 中太有效了,String 类型变量会temp
自动接受c
char 类型并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 Widening Primitive Conversion”上的简短说明。
Java 编译器可以将其解释为任何一种。
通过编写程序并查找编译器错误来检查它:
public static void main(String[] args) {
int result1 = 'a' + 'b';
char result2 = 'a' + 'b';
}
如果它是一个字符,那么第一行会给我一个错误,而第二行不会。如果它是一个 int,那么会发生相反的情况。
我编译了它,我得到了......没有错误。所以 Java 两者都接受。
但是,当我打印它们时,我得到了:
诠释:195
字符:Ã
当你这样做时会发生什么:
char result2 = 'a' + 'b'
执行隐式转换(从int到char的“原始缩小转换” )。
根据二进制提升规则,如果两个操作数都不是 double、float 或 long,则两者都被提升为 int。但是,我强烈建议不要将 char 类型视为数字,这会违背其目的。
虽然您已经有了正确的答案(在 JLS 中引用),但这里有一些代码来验证您int
在添加两个char
s 时是否得到了一个。
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
char
表示为Unicode
值,其中 Unicode 值由\u
后面的Hexadecimal
值表示。
char
与提升到的值的任何算术运算一样int
,因此 的结果'a' + 'b'
计算为
1.)应用Unicode
相应的值char
使用Unicode Table
2.) 应用 十六进制到十进制的转换,然后对Decimal
值执行操作。
char Unicode Decimal
a 0061 97
b 0062 98 +
195
例子
0061
(0*16 3 ) + (0*16 2 ) + (6*16 1 ) + (1*16 0 )
(0*4096) + (0*256) + (6*16) + (1*1)
0 + 0 + 96 + 1 = 97
0062
(0*16 3 ) + (0*16 2 ) + (6*16 1 ) + (2*16 0 )
(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 %
虽然Boann 的回答是正确的,但是当常量表达式出现在赋值上下文中时,有一个复杂的情况适用于它们的情况。
考虑以下示例:
char x = 'a' + 'b'; // OK
char y = 'a';
char z = y + 'b'; // Compilation error
到底是怎么回事?他们的意思是一样的,不是吗?为什么在第一个示例中将a 分配int
给 a是合法的?char
当常量表达式出现在赋值上下文中时,Java 编译器会计算表达式的值并查看它是否在您要赋值的类型范围内。如果是,则应用隐式缩小原语转换。
在第一个示例中,
'a' + 'b'
是一个常量表达式,它的值将适合 a ,因此编译器允许将表达式结果char
隐式缩小为 a 。int
char
在第二个例子中,
y
是一个变量,所以y + 'b'
不是一个常量表达式。因此,即使Blind Freddy可以看到该值适合,编译器也不允许任何隐式缩小,并且您会收到一个编译错误,指出int
无法将 an 分配给 achar
。
关于在这种情况下何时允许隐式缩小原语转换,还有一些其他注意事项;有关完整详细信息,请参阅JLS 5.2和JLS 15.28。
后者详细解释了常量表达式的要求。这可能不是你想的那样。(例如,仅仅声明y
asfinal
没有帮助。)