Data types


Different than python, different data can be categorized into primitive type data and reference type data.

Primitive type data:

There are only 8 primitive data types in java as described below, different types are sorted by the size of memory it takes in the same category.
  • Non-decimal numbers: byte, short, int, long
  • Decimal numbers: float, double
  • Characters: char
  • true/ false: boolean
  • Note: true and false are all lower case in Java, having incorrect capitalization when specifying data types would error. Additionally, notice that all primitive types are lowercase.

Although you would only be using int, double, char and boolean most of the times, it’s best if you could memorize all of them and the order of the memory it takes. If we input a non-decimal number without specifying what data it is, it will be considered an int, and if it was a decimal number, it would be treated as double. If you want to specify the data type, you would append a certain character as a indicator. For example, 3L for a long value, and 3.0f for a float value. Important: You cannot invoke methods, access the properties or instance variables from a primitive type data.

Reference type data

Any type that is not a primitive type is a reference type. That includes Arrays, Lists, String, Object, and any custom class you created. By convention, referenced data type are capitalized. You can call methods on a reference type object, list.size(), is called the size method on a variable named list. So what actually is the difference at the backend? Let’s say we currently have the following line

                    int num = 5;

        

Because int is a primitive type, in the machine the value 5 is directly stored in the memory location.

primitive_type

If we change to reference type and have the following code

            String s = “test”;

The variable s stores the location where the String is actually storing in memory.

string_type

Because of that behavior, you will be hearing a lot of “pointers” when we are discussing about objects since what’s stored in the variable are merely a “pointer” to the actual object. Let’s observe the following code:

     int[] array1 = {1, 2, 3};
        int[] array2 = array1;
        array2[0] = 9;
        // what does array1 look like after the execution? Remains the same or changed?

This is the first part where some people would get confused when just starting Java. Before analyzing the code, let me explain what it is doing. int[] is the data type for a int array. The first line, I declared an array that contains only int and call it array1. The right hand side is the initial value for the array. The second line, we are assigning the value inside array1 to array2. The third line we are modifying the 0th index of the array to 9. If you are unfamiliar with the array syntax, we will cover that more in depth in recitation 3.
So let’s see what happens. After the first line of code, we now have this:

array object

Again, because arrays are reference type object, the variable array1 simply stores the address of the array. Hence, what actually is copied over to array2 is just the address. Now we have

object reference before

As you can see, the two variables are referencing the same object. Hence if we change array2

object reference after

array1 will also change without you noticing. This is called a shallow copy or an alias of the object.

Primitive data conversion

Usually this happens when you are converting between non-decimal and decimals numbers. Let’s do some simple math.

1 + 2

As discussed above, since non-decimal numbers are treated as int by default. The resulting answer will conform to the data type that has the largest memory among all the elements in the statement. Because 1 and 2 are both int, the resulting answer will also be an int. However, if any elements in the statement is a decimal number, the resulting answer will be a decimal number regardless of memory size. For example,

                   1 + 2.0

       

will result into 3.0 instead of 3. This is important because if you only write 3, it would be considered a int for Java and hence points deduction.
A common pitfall is division, consider the problem

            9 / 2
       

4.5 right? Simple math! Turns out that Java doesn’t think so. Again, because both numbers are int, the answer should also be an int, however, 4.5 is not an int. So, what happens is Java truncates, not round the number to turn it into an int. If you want to get 4.5, simply make one of the numbers into a double would do the trick. 9.0 / 2 would result in 4.5.

Casting

Casting is an attempt to convert a data type. There are two different type of casting, implicit casting and explicit casting. Let’s talk about explicit casting first.

Explicit Casting

Explicit casting is probably what you are more familiar, it is converting a data type manually. The syntax for explicit casting is you enclose the data type you want to convert into in parenthesis, right next to the data you want to convert. For example,

(double)9 / 2

That would also return you a 4.5 because you converted 9 to a double before the divide operation. You can also cast a double to an int like

            (int)4.5

The answer will be 4, explicit casting also truncates the data if there will be some data loss, it is also called lossy conversion.

Implicit casting

Implicit casting happens, as the name implies, implicitly. It happens when you are storing a tyor data into a variable that is not the same data type. For example,

                    double num = 3;

        

The right-hand side is an int and it is storing into a double. Although different data type, the above line code works because of implicit casting done by Java. It doesn’t always work. I’ve came up with two rules. It would only work only if

  1. If you are converting a non-decimal number into a decimal number.
  2. If the two types are both non-decimals or both decimals, and you are converting from smaller size memory to a bigger size memory.

If it violates the rule, implicit casting would NOT work and result in compiling error. Let’s see that in action. Consider the following problems

  1. int a = 1.6;
  2. double b = 3L;
  3. long c = 1;
  4. float d = 3.0;

1 and 4 would caused compile error, why?

Table of precedence

Operation or Symbol Precedence level

  1. ()
  2. Dot access
  3. Casting
  4. !
  5. *, /, %
  6. +, -
  7. <, >, <=, >=
  8. ==, !=
  9. &&
  10. ||
  11. =

* Dot access refers to calling a method or access a field on an object. More will be explained in object and class

Increment and decrement

Consider the following code:

            (1)	int a = 2;
        (2)	a = a + 1;

        

The second line would increment a by 1, similarly, we can do

            a += 1;
        a++;
        ++a;
        

The above three lines does the exact same thing if they are a standalone statement. What is the difference? a++ is called post-incrementation and ++a is called pre-incrementation. Things gets confusing if they are put into a statement along with other elements. But for now let’s consider the following:

               1.System.out.println(a++);
        2.System.out.println(++a):
        

Are the above two statements the same? The answer is no. With post-incrementation, the value inside the variable is evaluated before the incrementation, then the variable is updated. Vice versa for pre-incrementation.
What will the following program produce?

            int num = 5;
            System.out.println(num++);
            System.out.print(“,”);
            System.out.println(num);

       

How about this?

            int num2 = 5;
            System.out.print(++num2);
            System.out.print(“,”);
            System.out.println(num2);

        

The answer is 5, 6 for the first one, and 6, 6 for the second one.

**Very important, pre-increment and post-increment only work for variables. What that means is 5++ does not give you 6. It does not compile. People often get this wrong.