Null, primitive data value and wrapper class in method call [duplicate] - java

This question already has answers here:
Why is the default type of Java integer literals int instead of long? [closed]
(7 answers)
Closed 7 years ago.
I have following code snippet
public class Sample {
public static void main(String[] args) {
test(1);//fine & output - int
test(1L);//fine & output - long
//test(null); fine & output - Integer
test(12233333333);//error
}
static void test(int a){
System.out.println("int");
}
static void test(Integer a){
System.out.println("Integer");
}
static void test(long a){
System.out.println("long");
}
static void test(Long a){
System.out.println("Long");
}
static void test(List<Integer> a){
System.out.println("List");
}
}
My question is,
Why number value always refer int(primitive type) but null refer the most specific method among the overloads?
Why we need to say implicitly 1L why it not taking long value if u give big number(1233333333333)?
Can u some one explain those?

Why number value always refer int(primitive type) but null refer the
most specific method among the overloads?
Because by default compiler refers to the 32-bit integer operation for number without suffix l OR L (for long).
Why we need to say implicitly 1L why it not taking long value if u
give big number(1233333333333)? Can u some one explain those?
As I said above it by default refers to the integer operation and for such a big number it is out of the range of the Integer as this number will be considered as integer without suffix l or L so it will refer to the method which takes int as parameter but error comes up that value is out of range.
Let's see what JLS says..
JLS 4.2
If an integer operator other than a shift operator has at least one
operand of type long, then the operation is carried out using 64-bit
precision, and the result of the numerical operator is of type long.
If the other operand is not long, it is first widened (§5.1.5) to type
long by numeric promotion (§5.6).
Otherwise, the operation is carried out using 32-bit precision, and
the result of the numerical operator is of type int. If either operand
is not an int, it is first widened to type int by numeric promotion.

1233333333333 is an int literal so you could use that but you would have to cast it to long in which case the compiler will do the conversion. It does not work because it is too large to be an int.
The reason the compiler cannot just assume it is long is because ithey would be inconsistent with 123 being an int.

Related

constant expression require in java switch case (field is final and initialized)

public static final Integer SAMPLE = 100;
public static void doSomething(int errorCode) {
switch (errorCode) {
case SAMPLE:
// ...
break;
}
}
I got constant expression required. if i change SAMPLE to int it will get fix. why ?
The relevant parts of the language spec are in JLS Sec 14.11:
Every case label has a case constant, which is either a constant expression or the name of an enum constant.
This explains why you can't use an Integer value: it's not a constant expression, since it is evaluated at runtime.
The fix is to change the case label to have a constant expression. To know what types are allowed, read on in the same section of the spec:
Every case constant associated with the switch statement must be assignment compatible with the type of the switch statement's Expression (§5.2).
and
The type of the Expression must be char, byte, short, int, Character, Byte, Short, Integer, String, or an enum type (§8.9), or a compile-time error occurs.
Since you can't have a constant wrapped primitive type (Character, Byte, Short or Integer: they're all evaluated at runtime), this means that case labels can only be:
char
byte
short
int
String
An enum constant
The easiest option is to change your declaration of SAMPLE to:
public static final int SAMPLE = 100;
Note that 100 is in the guaranteed-cached range of Integer.valueOf, so there is no cost of declaring the value as a primitive: where you need a boxed value, a value is used from the cache.
Switch can only work with some primitives (char, byte, short, int), enum values and Strings.
change it to;
public static final int SAMPLE = 100;
Actually the switch statement can work with Integer.
Source: https://docs.oracle.com/javase/tutorial/java/nutsandbolts/switch.html
The case is only working with constant values, e.g. primitives and compile-time String.
Your SAMPLE field that you pass to the case statement should be of primitive type.

Why unboxing doesn't work : Unresolved compilation error: Cannot cast from double to Long? [duplicate]

This question already has answers here:
Cast object (type double) to int
(3 answers)
Closed 5 years ago.
As per my understanding, Java automatically takes care of Autoboxing and Unboxing i.e., conversion of Primitives to Object Wrappers and vice a versa. However, unboxing doesn't seem to be working in below code.
public class TestMath {
public static void main(String[] args) {
Long resultLong = (Long) Math.pow(10, 10);
System.out.println(resultLong);
}
}
The above code gives me compilation error until I manually do unboxing by replacing (Long) with (long). I would like to understand the reason behind this.
The compilation error is as shown below:
Exception in thread "main" java.lang.Error: Unresolved compilation
problem: Cannot cast from double to Long
Math.pow(10, 10) returns a double, which can be auto-boxed into a Double, not into a Long.
If you explicitly cast the result to long, the compiler can auto-box the long to Long.
As to why (Long) Math.pow(10, 10) doesn't work - there is no conversion from double to Long defined in the JLS. The only supported boxing conversions are from a primitive to its corresponding reference type:
5.1.7. Boxing Conversion
Boxing conversion converts expressions of primitive type to corresponding expressions of reference type. Specifically, the following nine conversions are called the boxing conversions:
From type boolean to type Boolean
From type byte to type Byte
From type short to type Short
From type char to type Character
From type int to type Integer
From type long to type Long
From type float to type Float
From type double to type Double
From the null type to the null type
You misunderstood/confused with casting and boxing/unboxing. They both are different concepts.
Math.pow(10, 10)
That returns a double and boxing/unboxing happens between respective primitives and wrappers (int <=> Integer , long <=> Long). Not with other types (double <!=!> Long).
Since you are trying to assign a double to long value, the compiler giving you the error. However assigning to Double works.
Double resultLong = Math.pow(10, 10);
In the above line, pow method actually returns the type double and will be converted to Double as they both are a pair of primitive and wrapper.

ArrayList storing other than specified datatypes

I have an ArrayList with type Long,but i am trying to insert int value in it.I am expecting int should also be stored in ArrayList as int is smaller in size than long.
int i=1;
ArrayList<Long> obj=new ArrayList<Long>();
obj.add(i);//It is showing error that Storing int is not possible
Whereas the below one is possible
List item
long l=0;
int i=5;
l=i;
Please suggest the reason why ArrayList can't store lower value types.
This:
ArrayList<Long> obj=new ArrayList<Long>();
is declaring that the list will store objects of type Long. It's storing references, and you can't put an Integer in, since an Integer is-not a Long (from the point of view of an object hierachy)
Don't think of the issue in term of numbers. Instead, try this. You have a list of Cats. You can't store a Dog in there. But you could if the list was declared as a list of Animals.
You could declare the list to contain a Number (Longs and Integers are both Numbers), but the fundamental issue is why are you mixing integers and longs in this collection ?
You are doing this:
Long l = 0L;
int i = 5;
l=i;//Type mismatch: cannot convert from int to Long
not this:
long l = 0;
int i = 5;
l = i;
It is not an ArrayList matter, look at this for details.
You just need to cast it to a long to make the above code work:
obj.add((long)i);
Because you specified that the ArrayList contains "Long", it forces all objects that go into it to be Long. And since ArrayList can be used to store any type of data, not just numbers, it doesn't have built-in mechanisms to convert ints to longs for example. Different rules apply.
Java primitives, like int and long, allow automatic conversion to comply with the way that C and C++ work, since Java was based on these languages originally. But it doesn't lead to the cleanest/safest code, and so some other more modern languages have removed even this type of fuziness.
The long variable l also can't store lower value types. The assignment of i to l will implicitly do a Widening Primitive Conversion, and the value is stored as a long.
When you try to insert an int value into a List<Long>, you're implicitly trying to do two conversions:
Widening Primitive Conversion (int to long)
Boxing Conversion (long to Long)
That double conversion will not be applied implicitly, so you have to tell the compiler to do it, by forcing the widening primitive conversion using a cast:
obj.add((long)i);
You have declared obj to be a list of Long and thus it restricts you to use add
/**
* Appends the specified element to the end of this list.
*
* #param e element to be appended to this list
* #return <tt>true</tt> (as specified by {#link Collection#add})
*/
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
Note - where E is from the class definition ArrayList<E> extends AbstractList<E>
to primarily add only the type that your list should be consisting of. Hence changing the code as follows should work :
int i=1;
ArrayList<Long> obj=new ArrayList<Long>();
obj.add(Long.valueOf(i));
Also in your latter part the cast is taken care by the = operator as you assign it in following way :
l=i;
An ArrayList<Long> can only store instances of Long.
You can "apparently" store longs in it, because the long is autoboxed to a Long:
list.add(someLong)
gets compiled to
list.add(Long.valueOf(someLong))
Boxing conversion only applies from primitive to corresponding wrapper type: long to Long, int to Integer etc. It doesn't box an int to a Long, however. The compiler isn't that smart/lenient.
And Java doesn't widen an Integer to a Long, because widening isn't defined for those types: it's only defined for primitive numeric types.
You've just got to make the parameter a long, then it can autobox for you:
obj.add((long) i);
or, without autoboxing:
obj.add(Long.valueOf(i));
Note, in the latter case, int is an acceptable parameter for a method taking a long parameter because of widening conversion. Widening + autoboxing just isn't supported.

Why is an explicit cast not needed here?

class MyClass {
void myMethod(byte b) {
System.out.print("myMethod1");
}
public static void main(String [] args) {
MyClass me = new MyClass();
me.myMethod(12);
}
}
I understand that the argument of myMethod() being an int literal, and the parameter b being of type byte, this code would generate a compile time error. (which could be avoided by using an explicit byte cast for the argument: myMethod((byte)12) )
class MyClass{
byte myMethod() {
return 12;
}
public static void main(String [ ] args) {
MyClass me = new MyClass();
me.myMethod();
}
}
After experiencing this, I expected that the above code too would generate a compile time error, considering that 12 is an int literal and the return type of myMethod() is byte. But no such error occurs. (No explicit cast is needed: return (byte)12; )
Thanks.
Java supports narrowing in this case. From the Java Language Spec on Assignment Conversion:
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.
From Java Primitive Data Type reference:
byte: The byte data type is an 8-bit signed two's complement integer. It has a minimum value of -128 and a maximum value of 127 (inclusive).
Try returning 128 : ))
This will work byte b = 4 as long as value is within the range, but if you try something like byte b = 2000 you would get compiler error because it is out of range. 12 is in within range so you aren't getting error.

Need to understand Boxing in core java

I cant figure out how the int 7 is consider as object in below example.
The sifer(7) is consider to be method sifer(Object o). I am not able to get it how this happened. In one of my java reference book it says Int can be boxed to an Integer and then "widened" to an object. I am not sure what that means.
>> Class A
class A { }
>> Class B
class B extends A { }
>> Class ComingThru
public class ComingThru {
static String s ="-";
static void sifer(A[] ...a2)
{
s = s + "1";
}
static void sifer(B[] b1)
{
s += "3";
}
static void sifer(Object o)
{
s += "4";
}
public static void main(String[] args) {
// TODO Auto-generated method stub
A[] aa= new A[2];
B[] ba = new B[2];
//sifer(aa);
//sifer(ba);
sifer(7);
System.out.println(s);
}
}
Since there is no sifer(int) method, the compiler will try to find the "closest match". In this case, the other 2 sifer methods take arrays as parameters, which an int clearly isn't.
The last method, sifer(Object) can be applied to any objects, including an Integer so that's the method that is used for sifer(7).
The reality is a little more complex, and the JVM will look for a matching mathod in the following order:
an identity conversion
in your case: sifer(int) but there is no such method
a widening primitive conversion
in your case: sifer(long) for example, but there is no such method
a widening reference conversion
in your case: not applicable, int is not an object
a boxing conversion optionally followed by widening reference conversion
in your case that's what's happening: int is boxed to Integer which is widened to Object
an unboxing conversion optionally followed by a widening primitive conversion
in your case: not applicable
1. Above code provides an classic example of Method Overloading, along with AutoBoxing and Auto-UnBoxing which came by Java 1.5, cause manual Boxing and Unboxing was a pain.
2. The sifer(A[]... a2) and sifer(B[] b1) both accepts Array type Arguments in its parameter, which no way matches int. So now we are left only with sifer(Object o).
3. Now the int will be converted into Wrapper Object Integer Automatically.
You can verify it by doing this in snifer(Object o) method.
o.getClass().getName();
See this link for further details:
http://docs.oracle.com/javase/1.5.0/docs/guide/language/autoboxing.html
7 will be auto boxed to Integer which is an Object
Also See
java: boolean instanceOf Boolean?
Steps as below-
The int (7) was boxed to a Integer.
The Integer reference was widened to an Object (since Integer extends Object).
The sifer() method got an Object reference that actually refers to a Integer
object.

Categories

Resources