4

我有两段代码。一个有效,另一个无效,但两者似乎都做相同的事情。这有效:

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");}
}
4

5 回答 5

1

分配和方法重载决议的规则是不同的:

对于分配,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,并且 Ci <: Si。

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

于 2015-03-15T09:24:44.350 回答
0

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

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

此外,如果表达式是 、 、 或 类型的常量表达式(第byte15.28shortcharint

如果变量的类型是 、 或 ,并且常量表达式的值可以用变量的类型表示,则可以使用窄化原byteshort转换char

虽然调用上下文转换没有这样的规则。这就是为什么,您必须通过类型转换显式地告诉编译器进行转换:new Demo1().go((short)7);

现在,至于为什么会有这样的行为,我们想出的原因只是一个猜测(真正的答案,只有语言设计者知道)。

于 2015-03-15T09:17:13.467 回答
0

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

于 2015-03-15T09:22:09.170 回答
0

在赋值中,编译器很清楚要转换哪个参数:

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),这对于没有类型层次关系的每种类型都是一样的。

于 2015-03-15T11:40:06.120 回答
0

您必须将整数转换为短整数,如下所示:

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。

于 2015-03-15T09:08:30.077 回答