这里发生了什么? java分配问题OCJP

两段代码,一块有效,另一块没有,但两者似乎做同样的事情

这很有效

short s=7; 

但事实并非如此。 这给出了错误,无法将int赋值为short。 我默认知道一个整数的字面值是int但是如果它可以直接在上面分配,那么为什么不传递给方法呢?

 class Demo1{ public static void main(String[] args){ new Demo1().go(7); } void go(short s){System.out.println("short");} } 

赋值和方法重载决策的规则不同:

对于作业,JLS说:

此外,如果表达式是byte,short,char或int类型的常量表达式(第15.28节):

如果变量的类型是byte,short或char,则可以使用缩小的基元转换,并且常量表达式的值可以在变量的类型中表示。

对于重载解析, JLS 15.12.2.2。 说:

当且仅当满足以下两个条件时,方法m才适用于子类型:

对于1≤i≤n,要么:
* Ai <:Si(§4.10),或
* Ai可以通过未经检查的转换(第5.1.9节)和Ci <:Si转换为某种类型的Ci。

这里的Ai是传递给方法的参数的类型(在你的情况下为int ,因为7是一个int文字)。 Si是方法的forms参数的类型(在您的情况下short )。 Ai <: Si表示Ai是Ai <: Si的子类型。 int 不是 short的子类型(反之亦然),这就是编译器不接受new Demo1().go(7);原因new Demo1().go(7);

第一个变量初始化。 第二个是将参数传递给方法。 在Method中,您必须传递精确数据类型的变量。

该语言允许在赋值上下文中将常量int表达式缩小到short类型。 方法调用上下文也是如此。 相关的JLS部分是JLS§5.2和JLS§5.3 。

对于赋值上下文,我将列出确切的语句:

此外,如果表达式是byteshortcharint类型的常量表达式(第15.28节):

如果变量的类型是byteshortchar ,则可以使用缩小的基元转换,并且常量表达式的值可以在变量的类型中表示。

虽然调用上下文转换没有这样的规则。 这就是为什么你要通过类型转换明确告诉编译器进行转换: new Demo1().go((short)7);

现在,至于为什么会出现这种行为,我们提出的原因只是猜测(真正的答案,语言设计师只知道)。

您必须将整数强制转换为short,如下所示:

 short s = (short) 7; 

这应该工作。

您的代码应如下所示:

 class Demo1{ public static void main(String[] args){ new Demo1().go((short) 7);// change here. } void go(short s){System.out.println("short");} } 

在直接赋值期间隐式转换的原因以及在方法调用期间传递值时不存在的原因是由于赋值上下文和调用上下文之间的差异,这些差异由您所处的情况自行解释。它只是如何java编程语言有效。

我认为这是一个积极的因素,因为如果你的某些方法具有相同的名称但在参数中具有不同的数据类型,它可以帮助编译器决定调用哪种方法。 通过将给定值转换为参数中的数据类型,编译器将能够区分您正在调用的方法,如果参数中出现隐式转换,编译器将如何知道将哪种数据类型转换为参数,如果你有两个名称相同但参数不同的方法,比如int和short。

在赋值中,编译器清楚显示要转换的参数:

 short s=7; //here is no doubt that it must be cast to short 

在方法调用中,可能是虚拟的,它不是可判定的。

 go(7); //here it could be anything 

编译器尝试查找类型兼容的签名,即

 void go(Integer i); // via auto boxing void go(Number i); // autoboxing and supertype 

它不会尝试投射,即跟随不起作用:

 void go(short s); // short is neither a super type nor a subtype of int void go(byte b); // byte is neither a super type nor a subtype of int 

我宁愿不要期望go(new Integer(7))调用void go(Short s) ,并且对于没有类型层次关系的每个类型都是一样的。