CSC300 / CSC402: 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]
Base Type [10/24]
Boxing [11/24]
Unboxing [12/24]
Boxing [13/24]
Assignment and Parameters with Base 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 Base Values [21/24]
Arrays of Objects [22/24]
Arrays of Arrays of Base 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
eqa01
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
  package algs12;
  import stdlib.*;
  import java.util.*;
  public class Hello {
    public static void main (String[] args) {
      Trace.showBuiltInObjects (true);
      Trace.run ();   
      int[] x = new int[] { 11, 21, 31 };
      int[] y = new int[] { 11, 21, 31 };
      Trace.draw ();
      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
eqi03

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)
eqi04

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
eqo01

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
eqs01

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
eqs02

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
eqs03

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
eqs04

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

Base Type [10/24]

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

Base types are also called primitive 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
eqi01

Unboxing [12/24]

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

Boxing [13/24]

Conversion from base type to object type is called boxing.

Conversion from object type to base type is called unboxing.

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

For int and double, the operations are as follows

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

Java has six additional base types:

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

Assignment and Parameters with Base Types [14/24]

Very Important!

Both assignment, and passing a base type value as an argument to a method with a base 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
18
19
20
public static void main (String[] args) {
    Trace.showBuiltInObjects (true);
    Trace.drawStepsOfMethod("f");
    Trace.run ();
    int x = 35;
    int y = x;
    y += 10;
    y = f(y);
    Trace.draw();
}

public static int f(int y) {
    y *= 10;
    return y;
}
001-Value-Hello_f_19

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
31
32
33
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) {
    Trace.showBuiltInObjects (true);
    Trace.drawStepsOfMethod("f");
    Trace.run ();
    MyInteger x = new MyInteger(35);
    MyInteger y = x;
    Trace.draw();
    y.add(10);
    y = f(y);
}

public static MyInteger f(MyInteger y) {
    y.multiply(10);
    return y;
}
002-Reference-Hello_f_32

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
eqi08

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
eqi01

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
eqi08

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
eqi07

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
eqi02

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 Base 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
eqa01

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
eqa03

Arrays of Arrays of Base 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
eqa04

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
eqa05