CSC300: Boxing, Equality, and Memory

Contents [0/24]

Objects and equality [1/24]
Equals Operator and Equals Method [2/24]
Null on the Right [3/24]
Null on the Left [4/24]
Object [5/24]
String Literal [6/24]
String Constructor [7/24]
String Operators [8/24]
String Interning [9/24]
Primitive Type [10/24]
Boxing [11/24]
Unboxing [12/24]
Boxing [13/24]
Assignment and Parameters with Primitive Types [14/24]
Assignment and Parameters with Object Types [15/24]
Integers Close to Zero [16/24]
Integers Far from Zero [17/24]
Integer Boxing with valueOf [18/24]
Integer Constructor (Deprecated) [19/24]
Copying a Reference [20/24]
Arrays of Primitive Values [21/24]
Arrays of Objects [22/24]
Arrays of Arrays of Primitive Values [23/24]
Arrays of Arrays of Objects [24/24]

(Click here for one slide per page)


Objects and equality [1/24]

int[] x = new int[] { 11, 21, 31 };
int[] y = new int[] { 11, 21, 31 };
x=[I@8807e25, y=[I@2a3046da
x=[11, 21, 31], y=[11, 21, 31]
                  x==y : false
   Objects.equals(x,y) : false
           x.equals(y) : false
    Arrays.equals(x,y) : true
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
  package ds1.student;
  import stdlib.*;
  import java.util.*;
  public class Hello {
    public static void main (String[] args) {
    
      // Try drawing what these arrays look like when tracing manually.
      int[] x = new int[] { 11, 21, 31 };
      int[] y = new int[] { 11, 21, 31 };
      StdOut.println ("x=" + x + ", y=" + y);
      StdOut.println ("x=" + Arrays.toString(x) + ", y=" + Arrays.toString(y));
      StdOut.println ("                  x==y : " + (x == y));
      StdOut.println ("   Objects.equals(x,y) : " + (Objects.equals(x,y)));
      StdOut.println ("           x.equals(y) : " + (x.equals(y)));
      StdOut.println ("    Arrays.equals(x,y) : " + (Arrays.equals(x,y)));
    }
  }

Equals Operator and Equals Method [2/24]

In Java, == checks object identity on object types

Unlike other languages (such as C++) this behavior cannot be changed.

Objects all have an equals method.

The java.util.Objects class provides some handy utilities, like Objects.equals

Null on the Right [3/24]

Integer x = 3000;
Integer y = null;
x=3000, y=null
                  x==y : false
   Objects.equals(x,y) : false
           x.equals(y) : false

Null on the Left [4/24]

Integer x = null;
Integer y = 3000;
x=null, y=3000
                  x==y : false
   Objects.equals(x,y) : false
Exception in thread "main" java.lang.NullPointerException
  at algs12.Hello.main(Hello.java:15)

Object [5/24]

Try java.lang.Object

Object x = new Object();
Object y = new Object();
x=java.lang.Object@8807e25, y=java.lang.Object@2a3046da
                  x==y : false
   Objects.equals(x,y) : false
           x.equals(y) : false

String Literal [6/24]

Try java.lang.String

String x = "Hello";
String y = "Hello";
x=Hello, y=Hello
                  x==y : true
   Objects.equals(x,y) : true
           x.equals(y) : true

Java does this for efficiency.

String Constructor [7/24]

String x = new String ("Hello");
String y = new String ("Hello");
x=Hello, y=Hello
                  x==y : false
   Objects.equals(x,y) : true
           x.equals(y) : true

One of the guarantees of Java is that using new will always construct a new object.

String Operators [8/24]

String x = "Hel" + "lo";
String y = "Hel" + "lo";
x=Hello, y=Hello
                  x==y : true
   Objects.equals(x,y) : true
           x.equals(y) : true

Java is being efficient by looking for a canonical representation of the string.

String Interning [9/24]

String a = new String ("Hello");
String b = new String ("Hello");
String x = a.intern();
String y = b.intern();
x=Hello, y=Hello
                  x==y : true
   Objects.equals(x,y) : true
           x.equals(y) : true

String's intern method looks for a canonical representation of the string.

Primitive Type [10/24]

int x = 3000;
int y = 3000;
x=3000, y=3000
                  x==y : true

Primitive types are also called base types in Java.

Boxing [11/24]

Integer x = 3000;
Integer y = 3000;
x=3000, y=3000
                  x==y : false
   Objects.equals(x,y) : true
           x.equals(y) : true

Unboxing [12/24]

Integer a = 3000;
Integer b = 3000;
int x = a.intValue();
int y = b.intValue();
x=3000, y=3000
                  x==y : true

Boxing [13/24]

Conversion from primitive type to object type is called boxing.

Conversion from object type to primitive type is called unboxing.

The primitive types we will use in this course are mostly int and double.

For int and double, the operations are as follows

Primitive type Object type Boxing (primitive to object) Unboxing (object to primitive)
int primitive = 0; Integer object = null; object = Integer.valueOf(primitive); primitive = object.intValue();
double primitive = 0.0; Double object = null; object = Double.valueOf(primitive); primitive = object.doubleValue();

Java has six additional primitive types:

Primitive type Object type Boxing (primitive to object) Unboxing (object to primitive)
boolean primitive = false; Boolean object = null; object = Boolean.valueOf(primitive); primitive = object.booleanValue();
float primitive = 0.0F; Float object = null; object = Float.valueOf(primitive); primitive = object.floatValue();
byte primitive = 0; Byte object = null; object = Byte.valueOf(primitive); primitive = object.byteValue();
char primitive = 0; Character object = null; object = Character.valueOf(primitive); primitive = object.charValue();
short primitive = 0; Short object = null; object = Short.valueOf(primitive); primitive = object.shortValue();
long primitive = 0L; Long object = null; object = Long.valueOf(primitive); primitive = object.longValue();

Assignment and Parameters with Primitive Types [14/24]

Very Important!

Both assignment, and passing a primitive type value as an argument to a method with a primitive type argument, results in copying the data to a new place in memory.

Modifying the data in the new place in memory does not affect the memory where the data was copied from!

06
07
08
09
10
11
12
13
14
15
16
17
public static void main (String[] args) {
    // Try tracing the execution of method f
    int x = 35;
    int y = x;
    y += 10;
    y = f(y);
}

public static int f(int y) {
    y *= 10;
    return y;
}

Note: The assignment at line 13 has not been done yet!

The variable y in the main program still contains the value it had before f was called.

Assignment and Parameters with Object Types [15/24]

Very Important!

Assignment, or passing a reference to an object of some type to a method with an object type parameter results in copying the address of the object to a new place in memory.

This includes boxed types, arrays, and any other object for which a class is defined. Modifying the data in the object (if the object is mutable) affects what the calling code "sees".

06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
static class MyInteger {
    int value;
    MyInteger(int value) {
        this.value = value;
    }
    void add(int value) {
        this.value += value;
    }
    void multiply(int value) {
        this.value *= value;
    }
}

public static void main (String[] args) {
    // Try tracing the execution of this code.
    MyInteger x = new MyInteger(35);
    MyInteger y = x;
    y.add(10);
    y = f(y);
}

public static MyInteger f(MyInteger y) {
    y.multiply(10);
    return y;
}

Note: The variable y in the main program is simply an alias for the object also referenced by the variable x.

The variable y in the function f is pointing at the same object (although we wouldn't call it an alias here)!

Integers Close to Zero [16/24]

Integer x = 30;
Integer y = 30;
x=30, y=30
                  x==y : true
   Objects.equals(x,y) : true
           x.equals(y) : true

This is like what Java does with string interning -- boxed integers close to 0 are given a canonical representation.

Again, this is for efficiency.

Integers Far from Zero [17/24]

Integer x = 3000;
Integer y = 3000;
x=3000, y=3000
                  x==y : false
   Objects.equals(x,y) : true
           x.equals(y) : true

Java is using Integer.valueOf(3000) to box the integer. The boxed objects are distinct in memory.

Integer Boxing with valueOf [18/24]

Integer x = Integer.valueOf(30);
Integer y = Integer.valueOf(30);
x=30, y=30
                  x==y : true
   Objects.equals(x,y) : true
           x.equals(y) : true

Explicitly calling Integer.valueOf(30).

Java will provide the canonical representation for integers close to 0.

The boxed object returned in each case is the same, because 30 is close enough to 0.

Integer Constructor (Deprecated) [19/24]

Integer x = new Integer(30);
Integer y = new Integer(30);
x=30, y=30
                  x==y : false
   Objects.equals(x,y) : true
           x.equals(y) : true

Again, the new operator in Java guarantees the construction of a new object.

Copying a Reference [20/24]

Integer x = 3000;
Integer y = x;
                  x==y : true
   Objects.equals(x,y) : true
           x.equals(y) : true

y is now an alias for the object x was pointing to at the time the assignment x = y was performed.

Note: If you do an assignment, such as x = null after that, y would still point to the boxed integer with the value of 3000!

Arrays of Primitive Values [21/24]

Try arrays, with utility functions in java.util.Arrays

int[] x = new int[] { 11, 21, 31 };
int[] y = new int[] { 11, 21, 31 };
x=[I@8807e25, y=[I@2a3046da
x=[11, 21, 31], y=[11, 21, 31]
                  x==y : false
   Objects.equals(x,y) : false
           x.equals(y) : false
    Arrays.equals(x,y) : true

Arrays of Objects [22/24]

Integer[] x = new Integer[] { 11, 21, 31 };
Integer[] y = new Integer[] { 11, 21, 31 };
x=[Ljava.lang.Integer;@8807e25, y=[Ljava.lang.Integer;@2a3046da
x=[11, 21, 31], y=[11, 21, 31]
                  x==y : false
   Objects.equals(x,y) : false
           x.equals(y) : false
    Arrays.equals(x,y) : true

Arrays of Arrays of Primitive Values [23/24]

int[][] x = new int[][] { { 11, 21, 31 }, { 12, 22, 32 } };
int[][] y = new int[][] { { 11, 21, 31 }, { 12, 22, 32 } };
x=[[I@8807e25, y=[[I@2a3046da
x=[[I@12f40c25, [I@3ada9e37], y=[[I@5cbc508c, [I@3419866c]
                  x==y : false
   Objects.equals(x,y) : false
           x.equals(y) : false
    Arrays.equals(x,y) : false
Arrays.deepEquals(x,y) : true

Arrays of Arrays of Objects [24/24]

Integer[][] x = new Integer[][] { { 11, 21, 31 }, { 12, 22, 32 } };
Integer[][] y = new Integer[][] { { 11, 21, 31 }, { 12, 22, 32 } };
x=[[Ljava.lang.Integer;@8807e25, y=[[Ljava.lang.Integer;@2a3046da
x=[[Ljava.lang.Integer;@12f40c25, [Ljava.lang.Integer;@3ada9e37], y=[[Ljava.lang.Integer;@5cbc508c, [Ljava.lang.Integer;@3419866c]
                  x==y : false
   Objects.equals(x,y) : false
           x.equals(y) : false
    Arrays.equals(x,y) : false
Arrays.deepEquals(x,y) : true