What is happening here ? java assignment issue OCJ

2019-02-24 06:10发布

问题:

Two pieces of code, one works, another doesn't, but both seem to do identical things

this works

short s=7;

but this doesn't . this gives error , can't assign int to short. i knw a integer number literal by default is int but if it can be assigned directly above , then why not when passing to method?

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

回答1:

The rules are different for assignment and for method overload resolution :

For assignment the JLS says :

In addition, if the expression is a constant expression (§15.28) of type byte, short, char, or int:

A narrowing primitive conversion may be used if the type of the variable is byte, short, or char, and the value of the constant expression is representable in the type of the variable.

For overload resolution, JLS 15.12.2.2. says:

The method m is applicable by subtyping if and only if both of the following conditions hold:

For 1 ≤ i ≤ n, either:
* Ai <: Si (§4.10), or
* Ai is convertible to some type Ci by unchecked conversion (§5.1.9), and Ci <: Si.

Here Ai is the type of the parameter passed to the method (int in your case, since 7 is an int literal). Si is the type of the method's formal parameters (short in your case). Ai <: Si means that Ai is a sub-type of Si. int is not a sub-type of short (the opposite is true), which is why the compiler doesn't accept new Demo1().go(7);.



回答2:

First one Variable initialization. Second one is passing parameter to method. In Method you must pass exact data type of variable.



回答3:

The language allows the narrowing conversion of constant int expression to short type, in Assignment Context. The same is not true for method invocation context. Relevant JLS section is JLS §5.2 and JLS § 5.3.

For assignment context, I'll list down the exact statement:

In addition, if the expression is a constant expression (§15.28) of type byte, short, char, or int:

A narrowing primitive conversion may be used if the type of the variable is byte, short, or char, and the value of the constant expression is representable in the type of the variable.

While there is no such rule for invocation context conversion. That is why, you've to tell the compiler explicitly to do the conversion, by type-casting: new Demo1().go((short)7);

Now, as for why such a behaviour, the reason we come up with would just be a guess (real answer, language designer only knows).



回答4:

You must cast the integer to short as follows:

short s = (short) 7;

This should work.

Your code should look like this:

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

The reason for implicit casting during a direct assignment and it not being present when passing a value during a method call is due to the difference between the assignment context and the invocation context which are self explained by the situation you are in. It is just how the java programming language works.

I see it as a positive factor as it helps the compiler decide which method your are calling if some of your methods have the same name but have the different data types in the paramaters. With you casting the given value to the data type in the paramater, the compiler will be able to distinguish which method you are calling, if implicit casting were to occur in the parameter how would the compiler know which data type to cast it to, if you had two methods with the same name but different parameters, say int and short.



回答5:

In an assignment it is clear for the compiler to which argument to cast:

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

In a method call, which could be possibly virtual, it is not decidable.

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

The compiler tries to find a signature which is type compatible, i.e.

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

It does not try casting, i.e. following would not work:

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

I rather do not expect go(new Integer(7)) to call void go(Short s) and that is the same with every types that are in no type hierarchy relation.