Autoboxing Unboxing in java using Object - java

Using Object type object for autoboxing is working but it is not working for unboxing. What is the reason behind it. I mean about not working of unboxing feature for Object type object. Is any special reason to implement this behaviour. Because its support autoboxing but not support unboxing.When it comes to Integer class it support both autoboxing and unboxing. And c# also supports autoboxing and unboxing for Object type object.
class Demo{
public static void main(String args[]){
int x=100;
Object iob1=new Object();
Object iob2=x; //Auto Boxing
System.out.println(iob2.toString());
int y = x + iob1; //Unboxing is not working
int z = x + new Integer(10); // Unboxing is working
System.out.println(y);
}
}

Unboxing is working quite fine. BUT only for Double, Integer, etc.. iob1 is of type Object, so it can't work. The jls lists types that can be un-/boxed here.

int y = x + iob1;
The + operator cannot have an int and an Object (How do you expect to add a number to an object?). See this section from the Java Language Specification:
If the type of either operand of a + operator is String, then the operation is string concatenation.
Otherwise, the type of each of the operands of the + operator must be a type that is convertible (§5.1.8) to a primitive numeric type, or a compile-time error occurs.

Related

How does JVM makes raw type wrapper "Immutable" when passing function parameter?

I have a simple code snippet to test "Immutable" integer like below:
public static void changeInteger(Integer i) {
++i;
}
public static void main(String[] args) {
Integer i = new Integer(3);
++i;
System.out.println(i); // 4
ImmutableWrapper.changeInteger(i);
System.out.println(i); // still 4!
}
I could see as Java language design, a wrapper class Integer is immutable when passed as function parameter.
What confused me is, why the ````++i``` inside main() will increase the value, while passing into function, doesn't change?
I wonder how does Java compiler or JVM achieve this? I know that Integer is a reference type, so when passed as parameter, an reference is passed, and then ++i will change its wrapped value?
Wish technical explanation.
Autoboxing and unboxing is the automatic conversion that compiler helps us to converse between the primitive types and wrapper classes.
https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.15.1 says:
If necessary, the sum is narrowed by a narrowing primitive conversion (§5.1.3) and/or subjected to boxing conversion (§5.1.7) to the type of the variable before it is stored. The value of the prefix increment expression is the value of the variable after the new value is stored
So, ++i equals to i = Integer.valueOf(i.intValue() + 1)

Invoking method with different argument type

I am trying to understand inheritance from the Head First Java book. On page 193 I got everything right, and I am trying to invoke a method with a different parameter ( an overloaded method ), but the main class invokes the one inherited from the superclass. How can I invoke the following method?
boolean frighten(byte b) {
System.out.println("a bite?");
return true;
}
I tried to declare a byte, but it did not help.
Thank you guys, here are the codes:
public class MonsterT {
public static void main(String[] args) {
Monster[] ma = new Monster[3];
ma[0] = new Vampire();
ma[1] = new Dragon();
ma[2] = new Monster();
for (int x=0; x < 3; x++) {
ma[x].frighten(x);
}
byte y = 2;
ma[0].frighten(y);
}
}
class Monster {
boolean frighten(int z) {
System.out.println("arrrgh");
return true;
}
}
class Vampire extends Monster {
boolean frighten(byte b) {
System.out.println("a bite?");
return true;
}
class Dragon extends Monster {
boolean frighten(int degree) {
System.out.println("breath fire");
return true;
}
And the output is: arrrgh
breath fire
arrrgh
arrrgh
The point here is the difference between overloading and overriding - see this answer for more.
So your class tree looks as follows:
Monster
| |
Vamire Dragon
This means that the
frighten(int z)
method is availble by inheritance to all three classes and could be overloaded (= same types - as it has been in the Dragon class).
While the
boolean frighten(byte b)
Is an overriding (not the same type of parameter), so that you could call
frighten(byte)
and
frighten(int)
on your Vampire.
Another aspect that comes into play is object type casting.
So at the end all your objects are "Monsters in the monster array "ma" - and will be seen as monsters.
This will be changed to vampire by the cast that #The Scientific Method demonstrated in it's answer.
Without the cast the byte would be auto type casted to int.
You can do that by casting ma[0] to Vampire: ((Vampire)(ma[0])).frighten(y);
Why it does not work currently?
You can't do that with current structure of classes and methods because of Method Invocation Conversion, applied when you invoke frighten() on Vampire object with byte argument:
Method 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.
Specifically, what happens in your case, is a widening primitive conversion:
byte to short, int, long, float, or double
(in your case: from byte to int)
Try this, casting down Monster to vampire , because the object at ma[0] is a Vampire referenced by Monster.
((Vampire)ma[0]).frighten(y);

Overloading and Java types concepts

public class Class2 extends Class1{
public static void main(String[] args) {
Class2 c2 = new Class2();
c2.m3(10);
c2.m3(10.5f);
c2.m3('a');
c2.m3(10l);
c2.m3(10.5);
}
public void m2() {
System.out.println("M1 method of class2");
}
public void m3(int i) {
System.out.println("int argument");
}
public void m3(float j) {
System.out.println("float argument");
}
}
Getting error when trying to call c2.m3(10.5); Could you please assist why this is happening?
Getting error when trying to call c2.m3(10.5); Could you please assist why this is happening?
What's happening here is that you are passing a double to the m3() method, when you call m3(10.5), while you only have two m3() methods that accepts either an int or a float, so that's where your problem come from.
Just change your last line like this:
c2.m3((float) 10.5);
You need to cast the double value to a float or pass a float like 10.5f.
You're calling the method with the wrong type: It seems you intended to invoke this overload: void m3(float j); but that cannot be called with 10.5. The literal 10.5 is a double, and there's no method overload taking a double parameter.
You should change the call to c2.m3(10.5f) or add yet another overload with the signature void m3(double j)
Let's refer to the language spec §5.3 Invocation Contexts:
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
Basically, when you call a method, the arguments you give can only undergo one of the conversions described above.
If the type of the expression cannot be converted to the type of the
parameter by a conversion permitted in a loose invocation context,
then a compile-time error occurs.
You are trying to convert from a double (10.5 is a double literal) to a float, which is a narrowing primitive conversion, which is not permitted in an invocation context.
10 works as an argument because an identity conversion (from int to int) is allowed.
10.5f works because it is a float literal and an identity conversion (from float to float) is allowed.
'a' works because this is a primitive widening conversion (from char to int), which is allowed.
10l works because this is also a widening primitive conversion (from long to float).
For more information on the kinds of conversions, see §5.1.

What exactly is Autoboxing in Java

class BoxingExample1{
public static void main(String args[]){
int a=50;
Integer a2=new Integer(a);//Boxing
Integer a3=5;//Boxing
System.out.println(a2+" "+a3);
}
}
So in this example is the class Integer being created or what???
Autoboxing is the automatic conversion that the Java compiler makes
between the primitive types and their corresponding object wrapper
classes. For example, converting an int to an Integer, a double to a
Double, and so on. If the conversion goes the other way, this is
called unboxing.
Source
Integer a2=new Integer(a);//Boxing
That is not autoboxing. You are just building an Integer object using Integer's constructor with value 5.
Where the second statement
Integer a3=5;//Boxing
Is Actual autoboxing is the automatic conversion that the Java compiler makes between the primitive types and their corresponding object wrapper classes.

Java primitives and overloading

I have always heard (and thought of) Java as a strongly typed language. But only recently did I notice something that I have been using almost on a daily basis: int and double overloading.
I can write the following, and it is valid Java code:
int i = 1;
double j = 1.5;
double k = i + j;
But, if I have a method, one of whose arguments is a double, I need to specify it:
public static <K, V> V getOrDefault(K k, Map<K, V> fromMap, V defaultvalue) {
V v = fromMap.get(k);
return (v == null) ? defaultvalue : v;
}
When I call the above method on a Map<String, Double>, the defaultvalue argument cannot be an int:
getOrDefault(aString, aStringDoubleMap, 0); // won't compile
getOrDefault(aString, aStringDoubleMap, 0d); // compiles and runs just fine
Why does Java overload an int to double (just like it does in addition), and then autobox it to Double? I think the answer lies in how Java does operator overloading (i.e. the overloading happens in the + operator, and not from int to double), but I am not sure.
Here's hoping that SO can help me out on this.
That's because primitives don't work with generics. They need to be boxed.
For the invocation
getOrDefault(aString, aStringDoubleMap, 0); // won't compile
to work, Java would have to box the 0 to an Integer, then somehow convert that to a Double. That's not allowed by the language. It's similar to why you can't do
Double value = 3; // Type mismatch: cannot convert from int to Double
From the JLS, on invocation contexts
If the type of the expression cannot be converted to the type of the
parameter by a conversion permitted in a loose invocation context,
then a compile-time error occurs.
The type of the expression, 0, an integer literal, is int. Loose invocation contexts are defined as
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
int to Double is not supported by any of those.
If you simply had
public static void main(String[] args) throws Exception {
method(3);
}
public static void method(double d) {
}
it would work.
You're looking for the exciting section 5.2 of the Java Language specification.
Basically when you add an int and double it performs a widening conversion. But it doesn't know to do this when trying to Autobox an int to a Double. It's explicitly disallowed in fact.
Java does not support operator overloading(An exception is String concat (+)) operator.
double k = i + j;
Here what is happening is implicit casting.A data type of lower size is widened to a data type of higher size. This is done implicitly by the JVM.
And for getOrDefault, primitives wont work with generics.And here comes autoboxing.
When you call getOrDefault(aString, aStringDoubleMap, 0d);, the 0d will be autoboxed to Double object.
But JVM cannot autobox 0 to a Double object in your first case.
Java will not perform a widening primitive conversion (0 to 0d) and a boxing conversion (double to Double) implicitly.
Check this link
An implicit cast from int to double, followed by boxing to Double, is not allowed.
0 can be only autoboxed to Integer.
0d can be autoboxed to Double.
The int -> double conversion is a widening conversion. Widening conversions do not lose data, so they are performed automatically.

Categories

Resources