Why does this Number class assignment work (java)? - java

I looked for a duplicate of this but don't see a replica similar enough to satisfy.
You can't instantiate abstract classes in Java, and Number is abstract, so why does this line compile:
Number num = 3;
If it was Integer num, it would get autoboxed, but does autoboxing somehow work for Number too, even though it's abstract? Or is something else happening?

Integer is a subclass of Number, so 3 gets autoboxed from int to Integer, then the Integer gets stored in the Number variable.

It’s not that auto-boxing works for Number. You are fully correct, the Number class is abstract and cannot be instantiated. Also no general mechanism for auto-boxing a primitive number into a Number object exists in Java.
It’s that auto-boxing works from int to Integer. The literal 3 is an int (with no exception). And Integer is a concrete subclass of Number, so putting a reference to an Integer into a variable declared as Number is trouble-free.
It may be a bit surprising that it works, I agree with you. The basic rule of auto-boxing is you can put an int where an Integer is expected, a double where a Double is expected, and so forth. We can hardly say that an Integer was necessarily expected on the right-hand side of your initialization. It seems they have extended the rule to be applicable here anyway. And it’s no doubt in the JLS somewhere (JLS: Java Language Specification).
Just for checking we may do:
Number num = 3;
System.out.println(num.getClass());
Output:
class java.lang.Integer
You may extend the rule one step further:
Object obj = 3;
It still gives you an Integer (not just an Object even though Object is a concrete class).
Link: Similar question: Does Java autobox when assigning an int to an Object? (you will also find the references to JLS there)

Related

Is variable type the same as value type?

If I write:
int x = 7;
Can we conclude that the value type of 7 is int and therefore the type of x is also int?
What is 'int' indicating here? That the value is int or that 7 is an int?
int refers to x. It is indicating the type of the variable x. This is also informative of the type of the values that would be stored there.
int x =7;
Consists of 2 parts.
One is:
int x;
That declares x as an int in this scope. This shows that int refers to x.
The other part of the expression is:
x=7;
That actually assigns the int value 7 to x.Of course the assignment needs to be valid.So the value should be of a suitable type.
It also would be valid to omit the assignment in a program (if for example you do not use this variable.)
On the other hand you cannot omit the declaration since java is strongly typed.
For example writing:
y=8;
Does not give enough information unless y is declared.
y could be for example an int , Integer , long or Long.
What y is depends on its declaration.
It indicates that the variable x is of type int.
The expression 7 also happens to have type int, therefore the example is not that interesting.
Consider a more interesting example:
List<String> myList = new ArrayList<>();
Here, the compiler could infer that the type of new ArrayList<>() on the right hand side is ArrayList<String>. However, we might want to hide the concrete implementing class ArrayList, and instead declare myList to be of a more general type List<String>, which is a supertype of ArrayList<String>. This is useful if we want to prevent abstraction leak from the members of a class, or if we use myList as a local variable, and for some reason want to set it to an LinkedList later.
That's all I had to say on the question itself, but I want to give some context, and I want to argue that Java's current syntax is actually not too bad.
This syntax might seem verbose, one might think that one can often omit the type declaration on the left hand side. However, consider a language with stronger type inference.
For example, a closely related statically strongly typed language Scala tends to rely more on type inference. For example, if you write
var myList = List("foo", "bar")
it will automatically infer that myList is a variable of type List[String].
But this often leads to unwanted results. For example, given the assignment
var myList = List.empty
the Scala compiler would happily infer that the right hand side is a List[Nothing], where Nothing is a special type that signifies absurd impossible results "returned" by thrown Exceptions and Errors which break the normal program flow. You can't do anything with this variable. In order to make this variable useful, we have to write:
var myList: List[String] = List.empty
Now Scala compiler would understand that myList is supposed to be List[String], which is more general than the type inferred from the right hand side. As you can see: now you have both val keyword and an additional List[String]-type declaration on the left hand side, which is not necessarily much shorter than the corresponding Java version. It is actually longer, despite all the fancy type-inference magic. So, Java's syntax for variable declarations is... OK, at least it's not trivial to make it much better.

How does the increment operator work on an Integer instance if Java doesn't support operator overloading?

I read that Java does not support operator overloading. Then it made me wonder how you can use the increment operator on an instance of the Integer class.
Integer number = new Integer(10);
System.out.println(++number);
The above code compiles fine, without error. But let's say I made my own class, with only one member variable (an integer), and tried to use the increment operator. It would give me a compiler error. Why is this?
This is the sequence of operations that are performed when you call the increment operator on an Integer object:
Integer wrapper object is unboxed to an int primitive (using the intValue() method).
Primitive is incremented.
Incremented primitive is autoboxed to an Integer wrapper object.
So, in effect, the operator is actually applied to an int primitive, and not to an object. This behavior is only defined for objects of the primitive wrapper classes, and there is no way to make your own classes behave in a similar way.
See here for more info about autoboxing and unboxing.

How to test for equality for two ints in Java? [duplicate]

For example why can you do:
int n = 9;
But not:
Integer n = 9;
And you can do:
Integer.parseInt("1");
But not:
int.parseInt("1");
int is a primitive type. Variables of type int store the actual binary value for the integer you want to represent. int.parseInt("1") doesn't make sense because int is not a class and therefore doesn't have any methods.
Integer is a class, no different from any other in the Java language. Variables of type Integer store references to Integer objects, just as with any other reference (object) type. Integer.parseInt("1") is a call to the static method parseInt from class Integer (note that this method actually returns an int and not an Integer).
To be more specific, Integer is a class with a single field of type int. This class is used where you need an int to be treated like any other object, such as in generic types or situations where you need nullability.
Note that every primitive type in Java has an equivalent wrapper class:
byte has Byte
short has Short
int has Integer
long has Long
boolean has Boolean
char has Character
float has Float
double has Double
Wrapper classes inherit from Object class, and primitive don't. So it can be used in collections with Object reference or with Generics.
Since java 5 we have autoboxing, and the conversion between primitive and wrapper class is done automatically. Beware, however, as this can introduce subtle bugs and performance problems; being explicit about conversions never hurts.
An Integer is pretty much just a wrapper for the primitive type int. It allows you to use all the functions of the Integer class to make life a bit easier for you.
If you're new to Java, something you should learn to appreciate is the Java documentation. For example, anything you want to know about the Integer Class is documented in detail.
This is straight out of the documentation for the Integer class:
The Integer class wraps a value of the primitive type int in an object. An object of type Integer contains a single field whose type is int.
An int variable holds a 32 bit signed integer value. An Integer (with capital I) holds a reference to an object of (class) type Integer, or to null.
Java automatically casts between the two; from Integer to int whenever the Integer object occurs as an argument to an int operator or is assigned to an int variable, or an int value is assigned to an Integer variable. This casting is called boxing/unboxing.
If an Integer variable referencing null is unboxed, explicitly or implicitly, a NullPointerException is thrown.
(In the above text, the term "variable" means local variable, field or parameter)
Integer refers to wrapper type in Java whereas int is a primitive type. Everything except primitive data types in Java is implemented just as objects that implies Java is a highly qualified pure object-oriented programming language. If you need, all primitives types are also available as wrapper types in Java. You can have some performance benefit with primitive types, and hence wrapper types should be used only when it is necessary.
In your example as below.
Integer n = 9;
the constant 9 is being auto-boxed (auto-boxing and unboxing occurs automatically from java 5 onwards) to Integer and therefore you can use the statement like that and also Integer n = new Integer(9). This is actually achieved through the statement Integer.valueOf(9).intValue();
Integer is an wrapper class/Object and int is primitive type. This difference plays huge role when you want to store int values in a collection, because they accept only objects as values (until jdk1.4). JDK5 onwards because of autoboxing it is whole different story.
This is taken from Java: The Complete Reference, Ninth Edition
Java uses primitive types (also called simple types),
such as int or double, to hold the basic data types supported by the
language. Primitive types, rather than objects, are used for these
quantities for the sake of performance. Using objects for these values
would add an unacceptable overhead to even the simplest of
calculations. Thus, the primitive types are not part of the object
hierarchy, and they do not inherit Object.
Despite the performance
benefit offered by the primitive types, there are times when you will
need an object representation. For example, you can’t pass a primitive
type by reference to a method. Also, many of the standard data
structures implemented by Java operate on objects, which means that
you can’t use these (object specific) data structures to store primitive types. To
handle these (and other) situations, Java provides type wrappers,
which are classes that encapsulate a primitive type within an object.
Wrapper classes relate directly to Java’s autoboxing
feature. The type wrappers are Double, Float, Long, Integer, Short,
Byte, Character, and Boolean. These classes offer a wide array of
methods that allow you to fully integrate the primitive types into
Java’s object hierarchy.
int is a primitive type and not an object. That means that there are no methods associated with it. Integer is an object with methods (such as parseInt).
With newer java there is functionality for auto boxing (and unboxing). That means that the compiler will insert Integer.valueOf(int) or integer.intValue() where needed. That means that it is actually possible to write
Integer n = 9;
which is interpreted as
Integer n = Integer.valueOf(9);
In Java int is a primitive data type while Integer is a Helper class, it is use to convert for one data type to other.
For example:
double doubleValue = 156.5d;
Double doubleObject = new Double(doubleValue);
Byte myByteValue = doubleObject.byteValue ();
String myStringValue = doubleObject.toString();
Primitive data types are store the fastest available memory where the Helper class is complex and store in heap memory.
reference from "David Gassner" Java Essential Training.
int is a primitive type that represent an integer. whereas Integer is an Object that wraps int. The Integer object gives you more functionality, such as converting to hex, string, etc.
You can also use OOP concepts with Integer. For example, you can use Integer for generics (i.e. Collection<Integer>).
int is a primitive data type while Integer is a Reference or Wrapper Type (Class) in Java.
after java 1.5 which introduce the concept of autoboxing and unboxing you can initialize both int or Integer like this.
int a= 9
Integer a = 9 // both valid After Java 1.5.
why Integer.parseInt("1"); but not int.parseInt("1"); ??
Integer is a Class defined in jdk library and parseInt() is a static method belongs to Integer Class
So, Integer.parseInt("1"); is possible in java. but int is primitive type (assume like a keyword) in java. So, you can't call parseInt() with int.
To optimize the Java code runtime, int primitive type(s) has been added including float, bool etc. but they come along with there wrapper classes so that if needed you can convert and use them as standard Java object along with many utility that comes as their member functions (such as Integer.parseInt("1")).

Java and generics. Isn't 0 a Number?

What is that I'm missing about this snippet of code?
public class Zero<N extends Number> {
public N zero() {
return new Integer(0);
}
}
It says:
Type mismatch: cannot convert from Integer to N
Thanks!
Update I've changed the snippet to use an integer. Same thing happens. And it happens even when creating an anonymous subclass of Number. Could it be Eclipse that is faulty about this?
While an Integer is a Number, an Integer might not be compatible to N which can be any subclass of Number.
Integer is not guaranteed to be a superclass of N, so you can't just set an Integer value to an object of type N.
Think about it this way: If someone instantiates Zero<N> as Zero<Double>, the class effectively becomes:
public class Zero {
public Double zero() {
return new Integer(0);
}
}
which is obviously not valid.
Furthermore, you can't do return 0 either, because in the same manner, there is no way for the compiler to know how to convert it into N. (The compiler can only autobox types it knows about, but by using generics you widened the available types to also include custom implementations of Number.)
The problem with your code is that Java needs to be able to confirm that the return type of the function needs to be convertible to N extends Number for any N. So, in particular, if I were to instantiate the class with a Double, as in
Zero<Double> z = new Zero<Double>();
z.zero();
You'd run into trouble, because zero says that it returns a Double but it actually returns an Integer. The type error indicates that the compiler is concerned that something like this will happen.
To the best of my knowledge, there is no good way to do this in Java because generics are implemented via erasure; it can't know what the type of the argument is.
0 is an int, but since your method returns an object, it will be autoboxed to an Integer. The problem is that returning an Integer where any subclass of Number is allowed is not allowed by the compiler. That's simply because you can instantiate your class as
new Zero<Double>()
and in this case, returning Integer would not be compatible with the expected return type: Double.
When 'N' extends 'Number', 'N' becomes a specialization of 'Number' and you cannot assign an instance of a base class to a reference variable of it's specialization (upcast issue). This holds good while returning as well. A base class instance cannot be returned using the specialization type.

If class Number is abstract why I'm I allowed to write Number n = 5?

Number n = new Number(5) is illegal, but Number n = 5 isn't. Why?
Because of autoboxing. 5 is not an object so it is wrapped into an object (Integer in this case), and Integer is a Number.
Fundamentally, it's because Number is an abstract class - there is no constructor that corresponds to Number(5), and even if there was you still would not be able to instantiate the class directly because it's abstract.
As Bombe explains, in your second case you're really creating an Integer object* - which, as a subclass of Number, can be assigned to such a variable. And as it's a concrete class you can instantiate it.
*Although in practice it's actually more equivalent to Integer.valueOf(5), which on Sun JREs won't create an additional Integer object but will use a pooled version (like the Flyweight pattern).
It's similar to how the following would work:
List bob = new ArrayList();
List is an interface, so you can't instantiate it directly. However, you can declare a variable of type List and then assign to it a concrete object that implements that interface. Along the same lines, you can declare a variable of type Number and then assign to it any value object that is a concrete instance of that type. What you have done with the functional code is, for all intents and purposes (due to autoboxing):
Number n = new Integer(5);
It shouldn't be. autoboxing is a big mistake.

Categories