4

The following method accepts three arguments of type byte,int,int and the method is called from another method which gives a compilation error that the method parameters are not applicable for int,int,int.By default the byte parameter is not recognized until explicit casting is done.

 public double subtractNumbers(byte arg1,int arg2,int arg3) {
    double sum=arg1+arg2+arg3;
    return sum;
}

Now method calling in another method as follows

 public void call(){
  subtractNumbers(15,16,17);   /*Compile error,but 15 is in byte acceptable 
 range of -128 to 127 */
  }

If i change the above calling as subtractNumbers((byte)15,16,17); it works fine

When i declare a variable as byte c=15 it is accepted but when 15 is passed to a byte argument why there's a compile error;

int is the default literal for byte,short,int,long then why byte c=15 is accepted without casting but not method argument.

Thank you in advance.

Shashaank V V
  • 720
  • 1
  • 7
  • 19
  • it guess it's because of method overloading: you could have another `subtractNumbers` method with an int as the first argument, in which case, `subtractNumber(15,16,17)` would call the second one. – Maurice Perry Jul 09 '18 at 07:37
  • https://stackoverflow.com/questions/5193883/how-do-you-specify-a-byte-literal-in-java – SleepyX667 Jul 09 '18 at 07:39
  • by doing `(byte) 15` and `byte c = 15` you downcasted this `int` value into `byte`, so no compile error – benjamin c Jul 09 '18 at 07:45

3 Answers3

4

Your question boils down to:

Why does assigning 15 to a byte works in a variable declaration:

byte b = 15;

But not when calling a method?

subtractNumbers(15,16,17);

This is because those two situations are in two different contexts. The first is in an assignment context, while the second is in an invocation context.

According to the JLS §5.2 Assignment Contexts,

Assignment contexts allow the use of one of the following:

...

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.

15 is certainly a constant expression, so a narrowing primitive conversion from int to byte is allowed.

In an invocation context however, this is not true:

JLS §5.3 Invocation Context

Strict invocation contexts allow the use of one of the following:

  • an identity conversion (§5.1.1)
  • a widening primitive conversion (§5.1.2)
  • a widening reference conversion (§5.1.5)

Loose invocation contexts allow a more permissive set of conversions, because they are only used for a particular invocation if no applicable declaration can be found using strict invocation contexts. Loose invocation contexts allow the use of one of the following:

  • an identity conversion (§5.1.1)
  • a widening primitive conversion (§5.1.2)
  • a widening reference conversion (§5.1.5)
  • a boxing conversion (§5.1.7) optionally followed by widening reference conversion
  • an unboxing conversion (§5.1.8) optionally followed by a widening primitive conversion

"narrowing primitive conversion" is not mentioned, so it is not allowed in invocation contexts.

Sweeper
  • 213,210
  • 22
  • 193
  • 313
2

Java has this idea of compile-time narrowing. This allows the following to be valid at compile time:

byte b = 15;

Most people are taught that literal like 12 will default to int. This is not always true. Types like double, float and long has explicit literal (e.g. 15d, 15f and 15L), but non-floating point primitives below 32-bit does not.

That is why 15 is determined at compile-time to be of type byte.

In your case, the compiler is trying to perform type matching at compile time. The method subtractNumbers has a method signature of byte, int, int, so you must give it an exact match. Unfortunately, during this process, the compiler does not look at the list of available methods before inferring the type of 15. I believe this is due to method overload.

Consider this:

public static void test(byte a, int b){}
public static void test(int a, int b){}

Now if you call test(15, 16), if 15 is allowed automatic narrowing down to byte, then there would be ambiguity.

Jai
  • 8,165
  • 2
  • 21
  • 52
1

The reason is because when you try to cast a int to byte, you're doing a narrowing primitive conversion. Since this can cause a loss of information, the compiler requires you to do explicit casting (i.e. like what you did when you explicitly casted 15 to be of type byte in both cases). See this

To answer your other question as to why you can simply declare byte c = 15 without compile error, it is because 15 is still within the range of -128 to -127 which byte allows. If you try to assign a larger value such as byte d = 128, you'll still get a compile time error. See this

iridescent
  • 383
  • 1
  • 13