The difference between primitive types and reference types is one of Java's most controversial features, and developers often complain about the differences between primitive values and reference values.

  • Each primitive type is baked into the language.

    Java has eight primitive types.

  • Each reference type is a class or an interface.

    You can define your own reference type. So the number of reference types in Java is potentially endless.

Here's one of the primitive-versus-reference-type “gotchas:” You can't store a primitive value in an ArrayList. You can write

ArrayList<String> arrayList = new ArrayList<String>();

because String is a reference type. But you can't write

ArrayList<int> arrayList = new ArrayList<int>();

because int is a primitive type. Fortunately, each of Java's primitive types has a wrapper type, which is a reference type whose purpose is to contain another type's value. For example, an object of Java's Integer type contains a single int value. An object of Java's Double type contains a single double value. An object of Java's Character type contains a single char value. You can't create an ArrayList of int values, but you can create an ArrayList of Integer values.

ArrayList<Integer> arrayList = new ArrayList<Integer>();

Every primitive type's name begins with a lowercase letter. Every wrapper type's name begins with an uppercase letter.

In addition to containing primitive values, wrapper classes provide useful methods for working with primitive values. For example, the Integer wrapper class contains parseInt and other useful methods for working with int values:

String string = "17";
int number = Integer.parseInt(string);

On the downside, working with wrapper types can be clumsy. For example, you can't use arithmetic operators with Java's numeric wrapper types. Here's the way to create two Integer values and add them together:

Integer myInteger = new Integer(3);
Integer myOtherInteger = new Integer(15);
Integer sum =
  myInteger.intValue() + myOtherInteger.intValue();