Integer.class vs int.class
Asked Answered
R

5

46

What is the difference between Integer.class, Integer.TYPE and int.class?

acc to me

  1. Integer.class is a reference of Integer (Wrapper) Class object
  2. but what is then int.class as int is not a class, it's a primitive type. And what does Integer.TYPE refer to?
Reluctant answered 18/3, 2014 at 5:20 Comment(0)
T
26

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

Triad answered 18/3, 2014 at 5:44 Comment(3)
That last sentence may be in the javadocs, but it's wrong. :) You can also access those objects via int.class, boolean.class etc. I don't know when that functionality came in, so maybe the docs are just out of date there?Callous
i agree, interesting, why they said so, it's from Java 7Triad
@EvgeniyDorofeev how is this supposed to be the answer? The question was what's the difference between Integer.class, Integer.TYPE and int.classMucker
C
52

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
Callous answered 18/3, 2014 at 5:40 Comment(1)
How is it a shortcut, it literally takes longer to type.Kolyma
T
26

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

Triad answered 18/3, 2014 at 5:44 Comment(3)
That last sentence may be in the javadocs, but it's wrong. :) You can also access those objects via int.class, boolean.class etc. I don't know when that functionality came in, so maybe the docs are just out of date there?Callous
i agree, interesting, why they said so, it's from Java 7Triad
@EvgeniyDorofeev how is this supposed to be the answer? The question was what's the difference between Integer.class, Integer.TYPE and int.classMucker
B
2

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.

Burnette answered 18/3, 2014 at 5:25 Comment(2)
It's not schizophrenic. Integer is a class which holds a primitive of type int. It's a wrapper, a class by itself. I could define my own wrapper holding an int. It wouldn't be an alias to int or whatsoever. The fact you can use arithmetic operations on JDK wrappers is just because the JVM unwraps the primitive when needed by itself. There is only one type for ints, which is represented by what's returned by the call int.class. It is a totally different class from the Integer class, which is the type of the wrapper holding an int.Shishko
@MaximeOudot: yes indeed. It is just shizophrenic that there are two representations of the same value. Since Java 5, it also coerces often automatically between the two, which is more unsafe. Finally this also means that generics are automatically boxed which means there is often serious performance degradation. A higher level language should normally make abstraction for this, and let the compiler optimize this away, or for example use the type system to prevent people from using an collection of boxed Integers.Burnette
T
1

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

Terzas answered 18/3, 2014 at 5:22 Comment(3)
was asking what is Integer.TYPE and int.class then?Reluctant
One main reason I use Wrapper Primitives is that they allow null value.Draw
@Draw - good point.. But I guess the OP already knows this. :)Terzas
C
1

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
Cradling answered 10/12, 2020 at 8:48 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.