【问题标题】:How does narrowing work in method invocation in Java?缩小在 Java 中的方法调用中如何工作?
【发布时间】:2014-06-26 07:25:23
【问题描述】:

为什么会出现编译时错误? 2 在编译时是常量,因此此处应允许缩小,因为 2 在字节范围内。

public class Test {


 public static void main(String[] args) {

    ForTest test=new ForTest();
    test.sum(1, 2); //compile time error here

}

}
class ForTest
{

public int sum(int a,byte b)
{
    System.out.println("method byte");
    return a+b;
}
}

错误是: ForTest 类型中的 sum(int,byte) 方法不适用于参数 (int,int)。

编辑:我认为答案就在这里:http://docs.oracle.com/javase/specs/jls/se7/html/jls-5.html#jls-5.3 但我不明白 :(

【问题讨论】:

标签: java narrowing


【解决方案1】:

你要区分赋值转换方法调用转换

缩小原始转换范围

首先看JLS §5.1.3

对原始类型的 22 种特定转换称为缩小原始转换

  • [...]

  • int 为字节、短或字符

[...]

请注意,这仅解释了机制,而不是允许或不允许此类转换的地方。

作业转换

接下来看JLS §5.2

[...]

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

  • 如果变量的类型是 byte、short 或 char,并且常量表达式的值可以用变量的类型表示,则可以使用缩小原语转换。

[...]

这清楚地描述了在赋值byte b = 2 中允许从类型 int 到类型 byte 的缩小转换。

方法调用转换

但是,在阅读JLS §5.3 时,您不会阅读任何有关缩小转换的内容。所以编译器正在做正确的工作。

【讨论】:

    【解决方案2】:

    这是因为 2 被解释为 int,不能隐式转换为字节。

    您的选择是将方法签名更改为 (int a, int b),或显式进行强制转换:test.sum(1, (byte)2)

    【讨论】:

    • 它可以在赋值中隐式转换为字节,但这是一个例外。例如byte b = 2;
    【解决方案3】:

    您不能将 int 隐式类型转换为 byte。 调用方法为:

    sum(1, (byte)2); 
    

    【讨论】:

      【解决方案4】:

      修改后的答案:

      java 语言规范说,在寻找函数调用的候选匹配项时,在根据函数名称以及实际参数与形式参数的数量找到候选对象后,最终到达phase 2

      “如果 m 不是泛型方法,则 m 可通过松散调用适用,如果对于 1 ≤ i ≤ n,ei 在松散调用上下文中与 Fi 兼容,或者 ei 与适用性无关。”

      显然,当它到达第二个实际参数时,它决定一个“int”在“松散调用上下文”中与“字节”不兼容。因此,它拒绝了它在阶段 1 中找到的唯一匹配的候选者。

      我在 JLS 中找不到“松散调用”的正式定义。

      感谢 VikasMangal 和 KisHanarsecHaGajjar 指出我最初的答案的愚蠢之处,下面重复此答案以示永远的耻辱。

      cmets 所指的我的原始答案如下。

      Java 规范部分 5.1.3 说您应该能够做到这一点。

      另外在第 5.2 节关于常量分配的部分中提到

      “另外,如果表达式是字节、short、char 或 int 类型的常量表达式(第 15.28 节):

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

      但是,编译器似乎在走自己的路。

      【讨论】:

      • 能否提供参考链接?
      • 已修复,但必须向下滚动到 5.1.3,应该很容易找到。 -- 编辑了,没关系,找到了锚。
      • 哈哈,完全正确!我跳过了句子中的那个词,希望它们按从大到小的顺序排列。
      • @caskey 根据您的论点,2 可以用字节表示,而不是在此处自动键入强制转换。例如:字节 b=2;是允许的,因为 2 是 int 并且可以用字节表示
      • 不,问题是我引用了 java 语言规范,该规范涉及将常量分配给更窄类型的变量。这个实例是编译器,在这种情况下,我应该关心的是编译器规范。
      【解决方案5】:

      由于Narrowing Primitive Conversions(§5.1.3) 表示将int 缩小为byteshortchar。因此,您需要将int 转换为调用该方法的byte。像这样:

      test.sum(1, (byte)2);
      

      【讨论】:

        【解决方案6】:

        您可以使用原始整数实现更多功能。因此,每次您编写一个可以是“整数”值的值时,Java 都会自动进行强制转换,从而将其视为整数。

        当您尝试您在此处尝试的内容时,会发生相反的情况。 Java 看到一个可以作为整数的值,但要将其视为字节,您需要明确告知。这有点像说,好吧,我知道我在做什么,我确实意识到将数字转换为字节有其局限性,但我还是希望你这样做。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2020-09-23
          • 2019-05-11
          • 2011-04-17
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多