Java 为什么常量(字符)上的xor操作在使用变量时工作方式不同
请查看以下代码:Java 为什么常量(字符)上的xor操作在使用变量时工作方式不同,java,c#,c++,c,expression,Java,C#,C++,C,Expression,请查看以下代码: 案例1: 它工作得很好。 但当我使用变量而不是常量时,如下所示: 案例2: 在java语言中:案例1起作用,a的值为1,但案例2不起作用 在C和C++中:两种情况都是有效的,A值为1<P/P。 在C中:两种情况都不起作用 在javascript中:这两种情况都有效,这不是HLL,a的值为0 我知道java正在将变量转换为整数以进行二进制操作,但为什么它在案例1中有效而在案例2中无效,为什么同样的方法在C#中无效,以及为什么javascript中的值不同 更新 当我将变量设置为
案例1: 它工作得很好。 但当我使用变量而不是常量时,如下所示: 案例2: 在java语言中:案例1起作用,a的值为1,但案例2不起作用 在C和C++中:两种情况都是有效的,A值为1<P/P。 在C中:两种情况都不起作用 在javascript中:这两种情况都有效,这不是HLL,a的值为0
我知道java正在将变量转换为整数以进行二进制操作,但为什么它在案例1中有效而在案例2中无效,为什么同样的方法在C#中无效,以及为什么javascript中的值不同 更新 当我将变量设置为final时,它在java中的效果比在C#中的效果要好 但我仍然无法理解为什么常数是有效的,但当使用变量时,它们不是。以及为什么其他高级编程语言不会发生同样的情况。
我认为这是一个基本的操作,应该以相同的行为在所有编程语言中工作 注意:为了在javascript中测试上述所有情况,我在所有情况下都将“char”替换为“var”,并且它们都正常工作
只回答Java 表达式
'x'^'y'
是ax^y
不是,除非两个变量都声明为final
。此外,结果是int
^
是一个,这意味着两个操作数在求值之前都必须是整数类型char
升级为int
因此,您有了这个int
表达式,并尝试将其缩小为char
。在一般情况下,这可能会导致精度损失(int为4字节,char为2),因此编译器不允许您在没有明确说明它是您想要做的事情(通过转换为char
)的情况下执行此操作。但是,如果常量表达式的值适合新类型,则可以隐式缩小其范围。发件人:
- 如果变量的类型为
、字节
或短
,并且常量表达式的值可在变量的类型中表示,则可以使用缩小原语转换字符
直觉上,这是完全有道理的:错误是告诉你,你可能会失去精度,所以它希望你确认你知道这一点;从某种意义上说,这是一个响亮的警告。但是,如果编译器完全知道这不会发生,就像对常量表达式一样,那么它会使事情变得更容易,并“隐藏”该警告。在正常情况下,在执行操作之前,下列二进制运算符的操作数会“加宽” (摘自)
- 乘法运算符*、/、和%(§15.17)
- 数字类型+和-(§15.18.2)的加减运算符
- 数值比较运算符=(§15.20.1)
- 数值相等运算符==和!=(§15.21.1)
- 整数位运算符&、^和|(§15.22.1)
- 在某些情况下,条件运算符?:(§15.25)
char
操作数,加宽将把操作数转换为int
对于算术运算和位运算,运算结果的类型与两个操作数的“加宽”相同
当x
和y
具有typechar
时,表达式x^y
为您提供一个int
值。如果没有类型转换,则无法将其分配回char
,因此会出现编译错误
对于使用
char
literals的情况,同样的加宽过程也会发生。但该语言中有一个“特殊例外”,允许隐式缩小常量表达式的值,前提是常量表达式的值适合该类型。在这种情况下,'x'^'y'
将“适合”到字符中,因此允许赋值
<>对于常量表达式的异常,JLS引用是.< /P> < P>我将考虑C语言、C++语言和C语言。
在C#中,没有从整型到char型的隐式转换。根据ECMA 334标准“C#规范”第11.1.5节“整体类型”
•没有从其他类型到字符类型的隐式转换。
特别是,即使sbyte、byte和ushort类型
可使用char类型完全表示的值的范围,
不存在从sbyte、byte或ushort到char的隐式转换
因此,您需要显式地将运算符的结果强制转换为char类型。比如说
using System;
namespace ExclusiveOr
{
class Program
{
static void Main(string[] args)
{
char a = ( char )('x' ^ 'y' );
char c = 'x', d = 'y';
char b = ( char )( c ^ d );
Console.WriteLine("a = {0}, b = {1}", (int)a, (int)b);
}
}
}
输出是
a = 1, b = 1
根据C标准(第6.7.9节初始化)
4具有静态属性的对象的初始值设定项中的所有表达式
或线程存储持续时间应为常量表达式或字符串
文字
例如,这段代码将被编译
#include <stdio.h>
char a = 'x' ^ 'y';
int main(void)
{
printf( "a = %d\n", a );
return 0;
}
#include <stdio.h>
char c = 'x';
char d = 'y';
char b = c ^ d;
int main(void)
{
printf( "b = %d\n", b );
return 0;
}
但是,不会编译此代码
#include <stdio.h>
char a = 'x' ^ 'y';
int main(void)
{
printf( "a = %d\n", a );
return 0;
}
#include <stdio.h>
char c = 'x';
char d = 'y';
char b = c ^ d;
int main(void)
{
printf( "b = %d\n", b );
return 0;
}
在C++中,对于静态存储时间的对象没有这样的限制,所以所有与上面所示的C程序类似的程序的例子都会被编译。什么是确切的错误?没有C或C++的RePro?或者,你是指文件/命名空间范围?在这种情况下,仅C的错误:Java的整洁扭曲:如果x
和y
都是final
,它将编译!这两种情况都适用于c和c++@Bathsheba:反对票可能是因为这个问题太广泛了:对四种不同语言的不同解释。尽管如此,近距离投票会更好。这一推理对C#也是有效的,唯一的区别是ap
a = 1
#include <stdio.h>
char c = 'x';
char d = 'y';
char b = c ^ d;
int main(void)
{
printf( "b = %d\n", b );
return 0;
}
#include <stdio.h>
char c = 'x';
char d = 'y';
int main(void)
{
char b = c ^ d;
printf( "b = %d\n", b );
return 0;
}
b = 1