Just trying to understand the behavior of java.lang.Object class.
public class TypeCheck{
static void printMethod(Object obj)
{
System.out.println(obj);
}
public static void main(String[] args)
{
Object obj = new Object();
Integer intObj = new Integer(12);
String stringObj = new String("Hello");
printMethod(obj); //---> java.lang.Object#78b5f53a
printMethod(intObj); //---> 12
printMethod(stringObj); // ---> Hello
}
}
My questions are:
When should we use Object class?
But, when I only pass printMethod(intObj) and in printMethod(Object obj) I do an addition: System.out.println(obj+1) it does not work. If obj recognizes that it's an Integer, why can't I do operations on it?
Exception: TypeCheck.java:5: operator + cannot be applied to java.lang.Object,int System.out.println(obj+1);
Now, if I do this:
public class TypeCheck
{
static void printMethod(Object obj)
{
System.out.println(obj.getClass().getName());
}
public static void main(String[] args)
{
int i = 666;
printMethod(i);
}
}
It returns java.lang.Integer, but it's defined as int (primitive type). Why does Java convert a primitive type to it's wrapper class when passed to an Object.
Almost never. You should use as specific an object you can.
That should work. See below
Because primitives, i.e. int, are not objects. Therefore it needs to be made an object (boxed) to be passed as one.
EDIT in response to question edit:
(Number 2)
Inside of printMethod, the type of obj is not int, it is Object. You can't add objects! You would need to cast it back to Integer or int before you could perform such operations on it. What would the + do if you passed an instance of TypeCheck into TypeCheck.printMethod?
You rarely need to use Object itself. Object is a placeholder that contains default implementations of things like toString(), hashCode() and so on. You don't need to explicitly extend it to get these, though - every class inherits them automatically.
Java is a statically typed language, which means that type checking takes place at compile time to ensure all parameters are of the correct type, methods exist on the (declared) type of the objects they're being called on, and so on. The compiler doesn't know that you might pass an Integer into printMethod, and obj+1 makes no sense when obj is a string or a bare Object. You could cast it to an Integer, but of course this will break (ClassCastException) when you pass in a non-Integer.
Primitive types are not objects in Java. When the Java compiler sees code that uses a primitive type where an object is required:
int i = 5;
printMethod(i);
it compiles as if it were:
int i = 5;
printMethod(new Integer(i));
This is known as autoboxing and was introduced in Java 5 so that primitive types could be stored inside collections.
An addition (like in your second question) becomes something like:
// ... assume obj has been cast to an Integer ...
System.out.println(obj.intValue() + 1);
which of course makes no sense if obj were actually an Object, since it wouldn't have an integer value to begin with!
Question 1
When you have a list/array of different objects of different classes and you need to access each object. (I know this is bad and we should use Generics, but that is beside the point) Object is the superclass of all class and you can use it to reference any other objects.
Question 2
Cast it to Integer before you can perform addition as the addition operation belongs to the Integer class and not the Object class.
When you print a object, the toString() method is called. The implementation of toString() in Object class returns the pointer and the implementation of toString() in Integer returns the value of the integer. Depending on the type of the object, the corresponding toString() method will be called although the instance is the same.
Question 3
The other concept you have to understand is AutoBoxing. Java automatically converts your primitive int to Integer.
I believe you will rarely use Object directly. I mean you will mostly never instantiate it. The purpose of Object is to be a common parent to all other objects (all classes inherit from the Object class). So Object will define methods that all objects in Java are going to have, like toString. You will sometimes use an Object pointer to hold a class of unknown identity but, most of the time, you can find a closer parent to the candidate classes which can be held by this pointer.
When you pass intObj (which is an Integer, but can pass as an Object since Integer inherits from Object), it is not recognized by the method as an Integer. If it prints a number, it's because the toString method in the class Integer was overrided to print the value it represents, instead of the name of the class and its address. See it this way too... You can't do operations on the Integer in the printMethod, because printMethod doesn't know if it is going to be a raw Object, an Integer, or anything else. If you cast the Object as an Integer, it should get unboxed and the operation will succeed.
It's called autoboxing. Boxing is putting a primitive in an object which basicly only holds the primitive. So when you pass the int to a method which is waiting for an object, the int it boxed in an Integer and then passed to the method.
Related
When saying:
String str = "hello";
Object obj = str;
System.out.println(str==obj);
The result is true, because it points to the same objects in memory, which makes sense. But if I say:
obj.indexOf("h");
Or any subclass method, I get "cannot find symbol". They're still pointing to the same object, so what's going on during compile-time that makes reference objects of different types different from each other?
The Object type reference only knows about methods that are part of its public interface.
You have to cast if you know that Object reference is a String type:
int index = ((String) obj).indexOf("h");
Apples and Pears.
The identity check == is performed at runtime. And valid and fine.
The construct obj.indexOf... is a compile time error as class Object just does not have a method indexOf
If you tell the compiler (by means of casting) that obj contains a String, you can get valid code
((String)obj).indexOf("h");
Will compile again
I read this post: Is int an object in Java?.
In the post it is argued that int is not inherited from Object. If so is the case, then why does the code below compile without any error? Given that int is not Object and the signature of format() method is public static String format(String format, Object... args) as shown in documentation: javadoc for String!
public class Testing {
public static void main(String[] args) {
int integer = 7;
String str = String.format("%03d", integer);
System.out.println(str);
}
}
I have also read about "Autoboxing". What does this exactly mean? Are all the primitives replaced by appropriate Object's before compilation? If so, then is there any advantage of memory usage while using large array of int's (int[]) over Integer's (Integer[])? Similar arguments follow for double's etc.
Any insights are welcome.
It is caused by Autoboxing.
Here is a small snippet from the linked Java documentation that explains it better than I could:
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.
Here is the simplest example of autoboxing:
Character ch = 'a';
The rest of the examples in this section use generics. If you are not
yet familiar with the syntax of generics, see the Generics (Updated)
lesson.
Consider the following code:
List<Integer> li = new ArrayList<>();
for (int i = 1; i < 50; i += 2)
li.add(i);
Although you add the int values as primitive types, rather than
Integer objects, to li, the code compiles. Because li is a list of
Integer objects, not a list of int values, you may wonder why the Java
compiler does not issue a compile-time error. The compiler does not
generate an error because it creates an Integer object from i and adds
the object to li. Thus, the compiler converts the previous code to the
following at runtime:
List<Integer> li = new ArrayList<>();
for (int i = 1; i < 50; i += 2)
li.add(Integer.valueOf(i));
When calling String.format("%d",myInt), myInt is automatically (and implicitly) wrapped in an Integer instance, which extends Object, therefore it compiles.
Concerning the arrays, the conversion from primitiveType[] to WrapperClass[] is not automatic for some reason. If you try to use an array of a primitive type where an array of the wrapper class is expected, it will result in a compile error.
Using Integer creates an overhead compared to using int because you need to assign and store references. However, this overhead is limited when using Integer values between -128 and 127 because these values are pooled (which means that all instances of Integer wrapping a value in this in interval point to a unic reference).
Autoboxing is a help from the compiler, which automatically compiles something like
foo(i);
into
foo(Integer.valueOf(i));
when foo() takes an argument of type Object and you pass it a primitive type (int, in this case). It just makes the code easier to type and read.
And that's what happens here. The String.format() method expects objects as argument. You're passing it a primitive type, so the compiler autoboxes it to an Integer for you.
What is the difference between Integer.class, Integer.TYPE and int.class?
acc to me
Integer.class is a reference of Integer (Wrapper) Class object
but what is then int.class as int is not a class, it's a primitive type. And what does Integer.TYPE refer to?
Integer.class is, as you say, a reference to the Class object for the Integer type.
int.class is, similarity, a reference to the Class object for the int type. You're right that this doesn't sound right; the primitives all have a Class object as a special case. It's useful for reflection, if you want to tell the difference between foo(Integer value) and foo(int value).
Integer.TYPE (not Integer.type, mind you) is just a shortcut for int.class.
You can get a sense of this with a simple program:
public class IntClasses {
public static void main(String[] args) {
Class<Integer> a = int.class;
Class<Integer> b = Integer.TYPE;
Class<Integer> c = Integer.class;
System.out.println(System.identityHashCode(a));
System.out.println(System.identityHashCode(b));
System.out.println(System.identityHashCode(c));
}
}
Example output (it'll be different each time, but the first two will always be the same, and the third will virtually always be different):
366712642
366712642
1829164700
From java.lang.Class.isPrimitive API
There are nine predefined Class objects to represent the eight primitive types and void. These are created by the Java Virtual Machine, and have the same names as the primitive types that they represent, namely boolean, byte, char, short, int, long, float, and double.
These objects may only be accessed via the following public static final variables java.lang.Boolean.TYPE, java.lang.Integer.TYPE etc
Java handles primitive types versus class types in a schizophrenic way by defining two types for each primitive.
For instance int is the primitive type and Integer the class type. When you use generics, you are forced to use a non-primitive type so ArrayList<Integer> is allowed but ArrayList<int> not.
Since you sometimes want to perform reflection, this duality results in two classes (how else can you inspect a method public int foo ();).
Say you have a class:
public class Foo {
private Integer value;
public int value1 () {
return value;
}
public Integer value2 () {
return value;
}
}
The two methods will not always return the same value, since value2() can return null and value1() will throw a runtime error.
In plain terms :
int -- > Are primitives..for simple math operations. You cannot add them
to a collection.
Integer --> Are objects in themselves.. are wrappers to ints. i.e,
they can be used with collections (as they are objects). They are
collected as normal objects by the GC.
EDIT :
public static void main(String[] args) {
int i = 5;
System.out.println(int.class);
Integer i1 = new Integer(5);
System.out.println(Integer.TYPE);
}
O/P : int
int
So, basically, both return an int. Integer.TYPE just returns the primitive type of the Integer class. It is true for any wrapper class
To me, the easiest way to understand int.class and Integer.class is to stop thinking Integer is a wrapper (which kind of implies it is "special"). In fact, it is easier, and probably more appropriate, to think of int as a special case.
Integer is just a normal Java class, nothing different from e.g. String. It derives from Object, operates like Object, At runtime you can create an instance of Integer, the instance takes an object-like memory layout, e.g. with a pointer at the beginning pointing to the Integer.class, which is what enables the polymorphic runtime behavior of java.
There is really nothing special yet about Integer. if you imagine a Java without boolean, int, long these primitives, but only with Integer, Boolean, Long etc, the type system is actually very consistent.
Conceptually, you can think of int as a special class introduced later for performance reasons. Initially, it has nothing to do with Integer. At the time when Java was created, maintaining an object-like memory layout for plain numbers is very expensive for arithmetic heavy programs. And most of the arithmetic operations do not even involve polymorphic dynamic dispatching at all. E.g. it is a lot less common to invoke methods such as toString on a number.
int is special in the sense that it is a class whose "instances" are laid out in memory with the common object structure stripped off - just four consecutive bytes with no extra meta data.
As a result, you cannot do 123.getClass() because the runtime memory layout of int 123 does not have a class pointer. int.class does exist, it is completely unrelated to Integer.class (yet). In a sense, int is more similar to Void, as in Void.class does exist, but you can never have object o where o.class == Void.class.
Java could just settle here, int is int, Integer is Integer. But what people realize is that although less common, it is still very useful to be able treat int as a normal Java object otherwise you will always have to maintain two sets of your methods at least - one that takes normal objects, and another one that takes primitives - even though performance is not your concern. In these scenarios, int is actually behaving like Integer. Java allows this conversion to automatically happen through the processes of auto-boxing, hence effectively making int and Integer related.
But int is still int, and Integer is still Integer (e.g. int.class != Integer.class). But one extra field is introduced to Integer.class to indicate it relates to int.class, that is Integer.TYPE. So Integer.TYPE == int.class. To me Integer.TYPE is just to capture the notional that Integer and int are related. How to use it, or whether it is even useful, is up to you.
In practice, int and Integer are still separate types where it matters. For example:
void accept (int value);
void accept (Integer value);
are still considered two overloads. Hence when working with reflection, you can use int.class and Integer.class to differentiate between the two.
When not working with reflection or some form of meta programming, because you cannot navigate to int.class from an object, it is relatively rare to see int.class to be used in your code. Sometimes it feels confusing because auto-boxing syntax seems to suggest you should be getting int.class:
int value = 1;
Class c = ((Object)value).getClass();
But that is just an illusion, as the moment you do ((Object)value), you are actually creating a new Integer instance with the same value.
The only time I need to explicitly work with int.class and Integer.class is to build a generics api <T> T getValue(String name, Class<T> type); where I need to differentiate if the api is allowed to return null:
int value = getValue("key", Integer.class); // will potentially throw NPE
int value = getValue("key", int.class); // will never throw NPE
Let's consider the following code in Java.
package obj;
final class First
{
public int x;
public First(int x)
{
this.x=x;
}
}
final class Second
{
public Second(First o)
{
o.x=10;
}
}
final public class Main
{
public static void main(String[] args)
{
First f=new First(50);
Second s=new Second(f);
System.out.println("x = "+f.x);
}
}
In the above code, we are supplying a value 50 through the statement First f=new First(50); which is being assigned to a class member x of type int in the constructor body in the class First.
In the class Second, the object f of the class First is being passed through the statement Second s=new Second(f); and we are modifying the value of the instance variable x held in that object to 10 which will affect the original object f because in Java objects are always passed by reference and not by value.
In some specific situations, it may be crucial not to allow such changes to the original objects. Is there any mechanism in Java that may allow us to prevent such modifications? (that might allow us to pass objects by value)
No, the object isn't being passed at all in Second. The reference is being passed by value.
Java always uses pass-by-value, but the value of any expression is only ever a primitive type or a reference - never an object.
It sounds like you want to create a copy of an existing object, then pass a reference to that new object to the method (by value). Quite what constitutes a "copy" will depend on the data in the class. (You may be able to get away with a shallow copy, or you may need to go deeper etc.)
No, there aren't. I would say that your example is not a very good one: if you want to ensure that something doesn't change, don't provide ways to change it. Causing the change to be lost afterwards is misleading at best.
First f=new First(50);
Second s=new Second(f);
in first line you are create a reference variable of Object type First and in 2nd line it is pass to Class Second
So as Jon Skeet say in java "Java always uses pass-by-value, but the value of any expression is only ever a primitive type or a reference - never an object."
And if if u don't want to change the value of property then u must be pass new object of class First
Because if u have a reference of any class then u can change the property of that class ..
Or u can create a copy of that object which is at the end creating a new object of First Class
I can't understand why the overloaded function 'increase' does not change Integer but does change Point.
The propuse of 'Integer' class is to wrap int so it will be a reference Type.
import java.awt.Point;
public class test2 {
public static void main(String[] args) {
///1
Integer i = new Integer(0);
increase(i);
System.out.println(i);
///2
Point p = new Point(0,0);
increase(p);
System.out.println(p);
}
public static void increase(Integer i){
i = 1;
}
public static void increase(Point p){
p.setLocation(1, 1);
}
}
the output is :
0
java.awt.Point[x=1,y=1]
Also, is their a simple way to pass a variable to a function by reference in Java?
Integer class is an immutable class, that means its content can't be changed after it's created.
Also, Java is pass-by-value so the variable i is passed by value, and the fact that it changes inside the function has no effect on the caller.
Read here: http://en.wikipedia.org/wiki/Immutable_object for more information on immutable objects.
The simple answer is that Java uses pass by value, not pass by reference.
In the Point case, the method is changing a field of the point object whose reference was passed into the method.
In the Integer case, the method is simply assigning a new value to the local variable i. This does not update the variable i in the calling method, because Java uses pass by reference.
The other issue is that Integer has no setValue methods because it is immutable. If you want to do the equivalent of what the Point version of the method is doing, you will have to define an IntegerHolder class that has both a getter and a setter, together with methods such as increase, that your application needs. (Alternatively, find such a class in a 3rd party library.)
Integer objects are immutable, i.e. you can't change them. If you could, the syntax would be like
i.setValue(1);
If you want to pass a non-object by reference, you can either wrap it in an array of length 1 or (better) create a trivial wrapper. However, there is little reason to do so - don't port your code from C 1:1. Usually, you should have a semantically loaded object, like an Account on which you can call the increase and decrease (or maybe just setBalance) methods.
In this function:
public static void increase(Integer i){
i = 1;
}
autoboxing makes this equivalent to:
public static void increase(Integer i){
i = new Integer(1);
}
i.e. it changes the reference that i contains, not the value that it contains. The Integer object is itself immutable, there's actually no way to change the value of one after it has been created.
Since that reference is a local variable, any changes to it will not affect the variable that was passed in.
When you write i = 1, you are changing the i parameter to point to a new boxed Integer instance.
The original Integer instance that you passed to the function is not—and cannot be—changed—Integers are immutable
Answer here: http://www.javaworld.com/javaworld/javaqa/2000-06/01-qa-0602-immutable.html
This reference could be useful: http://javadude.com/articles/passbyvalue.htm
If you wanted the two methods to be equivalent, the second one would look like this:
public static void increase(Point p){
p = new Point(1, 1);
}
And then you would see that it outputs the original point here, too.
There is no pass a variable to a function by reference in Java.
You can simulate it by passing an object which contains the variable (like you did in your increase(Point) method) - you'll have to be sure to assign to the variable, though, not to the object containing the variable.
As said before, there are several "mutable wrappers" around (for example org.omg.CORBA.IntHolder and java.util.concurrent.AtomicInteger in the standard API), but it is not difficult to create your own, and in most cases it would be better to use a sensible "Business object" like an "Account" instead.