【问题标题】:Assignment issue OCJP; why can't I pass an int to a short?分配问题 OCJP;为什么我不能将 int 传递给 short?
【发布时间】:2015-03-15 09:01:17
【问题描述】:

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

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

【问题讨论】:

    标签: java variable-assignment method-invocation


    【解决方案1】:

    赋值和方法重载解析的规则不同:

    对于分配,JLS 说:

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

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

    对于重载解决方案,JLS 15.12.2.2. 说:

    当且仅当两个 以下条件成立:

    对于 1 ≤ i ≤ n,或者:
    * Ai <: si> * Ai 可通过未经检查的转换(第 5.1.9 节)转换为某种类型的 Ci,并且 Ci <: si.>

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

    【讨论】:

    • 但是,short 真的是 int 的子类型。如果是这种情况,我应该能够将 short[] 分配给 int[] 。程序不会编译。但是您可以将 Integer[] 分配给 Number[],因为 Integer IS-A Number 。但是,intshort 之间没有这种关系,除了 int 可以容纳任何 short 可以但仍然不是其他恕我直言的子类型!
    • 对于原始类型,它与继承不同的子类型关系。它被定义为here
    • JLS 还可以而且很全面,但我是否必须真正完成所有这些才能通过我的认证。我时间有限,请帮助!当然,一旦我开始工作,我可以阅读 JLS ,但我是否必须阅读所有这些才能清除我的 OCJP 。谢谢你。是的,我知道 OCJP 提出了一些棘手的问题
    • @Sarabjeet 每当遇到我不理解的行为时,我都会搜索 JSP。不能指望您阅读完整的 JLS(或者,就此而言,阅读任何 Java 书籍)并记住它。
    【解决方案2】:

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

    【讨论】:

      【解决方案3】:

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

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

      另外,如果表达式是一个常量表达式(§15.28) 输入byteshortcharint

      如果类型为 变量为byteshortchar,常量的值 表达式可以用变量的类型来表示。

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

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

      【讨论】:

        【解决方案4】:

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

        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。

        【讨论】:

        • 我知道通过在传递给 7 时将 7 转换为 short 会起作用,但是当直接分配时,编译器提供了隐式转换,以使分配工作,那么为什么它不提供相同的方法调用
        • 首先,我们都知道整数字面量默认值为int。因此,文字 7 的类型为 int,即使它可以分配给 shortbyte,因为它属于两者的范围。但是,编译器提供了隐式转换。这就是 short s=7 编译的原因,因为它实际上是被隐式转换的 short s=(short)7 ,但是当涉及到与上述方法调用一样的方法调用时,没有提供相同的隐式转换。常识认为它应该是,但事实并非如此。错误将是go(short) cannot be applied to int
        • 方法匹配,即决定哪个方法将被调用用于该方法的特定调用[在方法重载的情况下]是在编译时决定的。所以我想知道为什么它在编译时决定 7 确实很短,因此隐式转换它。我的意思是它在将文字分配给短变量时做同样的事情
        • 我认为这是一个积极因素,因为如果您的某些方法具有相同的名称但参数中具有不同的数据类型,它可以帮助编译器确定您正在调用的方法。通过将给定值转换为参数中的数据类型,编译器将能够区分您正在调用哪个方法,如果参数中发生隐式转换,编译器将如何知道将其转换为哪种数据类型,如果你有两个同名但参数不同的方法,比如 int 和 short。
        • 谢谢,你的观点确实有道理,但为了 OCJP 考试,我需要某种规则据我所知,一般规则是“原始扩展”优于“当两个选项都存在时自动装箱,并且当两种方法都存在时,“自动装箱”优于“var-args”。我希望我们可以为 OCJP 考试定义一种通用规则。谢谢你能帮上忙
        【解决方案5】:

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

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

        【讨论】:

        • 据我所见,一般规则是当两个选项都存在时,“原始扩展”优于“自动装箱”,并且当两种方法都存在时,“自动装箱”优于“var-args”在那儿 。我希望我们可以为 OCJP 考试定义一种通用规则。谢谢你能帮上忙
        猜你喜欢
        • 1970-01-01
        • 2019-10-26
        • 1970-01-01
        • 2017-12-11
        • 1970-01-01
        • 2017-07-20
        • 2012-11-10
        • 1970-01-01
        相关资源
        最近更新 更多