References, Autoboxing, and Unboxing
Summary
This lab provides background and experience with primitive types,
references to objects, autoboxing, and autounboxing in Java.
Acknowledgment
Much of this lab is edited from materials by Samuel Rebelsky:
Reading
Please read the following as preparation for this lab:
Variables for Primitive Types, Objects, and Immutable Objects
As noted in
the Reading
on Reference Values in Java,
-
Java's primitive types are analogous to C's basic data types (e.g., ints,
floats, doubles, and chars). That is, the compiler allocates separate
space for each declared variable.
-
Objects in Java are allocated in dynamic memory and thus are analogous to
nodes in C which are explicitly allocated. That is, new in Java
corresponds roughly to malloc in C. (An object in Java includes
both data and methods, while a struct in C includes only data.
This makes Java's objects more general than C's structs, but the idea
of memory allocation is generally similar.)
-
Copy the following two Java classes to your account for inclusion in
a references package.
Compile and run Experiments1.java and answer the following:
-
Do int variables int1 and int2 represent two
distinct memory locations, or do they refer to the same memory location?
Explain how you know.
-
What does the statement int int2 = int1 do regarding memory
allocation and processing? To what extent does this experiment in Java
seem similar to or different from your experience in C?
-
Does the statement int1 += 5 change both int1
and int2, or just int1? Explain why this result is obtained.
-
Do Tally variables tally1 and tally2 represent two
distinct objects and memory locations, or do they refer to the same object?
Explain how you know.
-
In the Tally class, comment out the definition
of toString, so that the compiler will use a default specification
(giving the object's address). Does this experiment support your
conclusion in Step d? Explain briefly.
-
Restore the toString method in Tally for this and
subsequent steps. What does the statement Tally tally2 = tally1
do regarding memory allocation and processing? To what extent does this
experiment in Java seem similar to or different than your experience in C?
-
Does the statement tally.tally () change both tally1
and tally2 or just tally1? Explain why this result is
obtained.
-
Moving on to integer1 and integer2, both of these refer
to objects, such as tally1 and tally2.
- Do you think these refer to the same object or to different objects?
- What do you think the statement integer1 += 5 means, as an
operation for an object referenced by integer1?
- Does a change in integer1 also change integer2,
analogous to tally1 and tally2?
Note: You may find it takes the rest of this lab to explain why
Java gives this result!
Normal Calling Mechanisms
-
Copy Experiments2.java
to your references package in Java.
Consider the following instructions.
System.out.println("square(bigi): " + square(bigi));
System.out.println("sqr(littlei): " + sqr(littlei));
System.out.println("bracket(str): " + bracket(str));
System.out.println("bigSum(bigvals): " + bigSum(bigvals));
System.out.println("littleSum(littlevals): " + littleSum(littlevals));
System.out.println();
In each case, the method (Java's jargon for function) is declared
specifying a parameter of a specific type, and the call to the method
supplies exactly this type of parameter.
-
Do you expect the Java compiler to accept these instructions? Why or why not?
-
If the Java compiler accepts these instructions, what output would you
expect to see when you run the program?
-
Check your answers to a and b experimentally.
Matching Primitives (e.g., int) or Wrapper Classes
(e.g., Integer) with String Types
-
Add the following instructions to the main method of
the Experiments2.java class.
System.out.println("bigi: " + bigi);
System.out.println("littlei: " + littlei);
System.out.println();
These examples illustrate how Java handles the primitive int and the
wrapper class Integer when a String is expected.
-
Method bracket expects a String object as parameter.
What happens when the main tries to pass parameters Integer
bigi or the int littlei into bracket as a
parameter that is supposed to be a String?
-
Do you expect the Java compiler to accept these instructions? Why or why not?
-
If the Java compiler accepts these instructions, what output would you
expect to see when you run the program?
-
Check your answers to a, b, and c experimentally.
-
What, if anything, does this exercise suggest about the use of primitives
or objects when a String is expected?
-
With this background, consider the following instructions.
System.out.println("parenthesize(str): " + parenthesize(str));
System.out.println("parenthesize(bigi): " + parenthesize(bigi));
System.out.println("parenthesize(littlei): " + parenthesize(littlei));
System.out.println();
-
Do you expect the Java compiler to accept these instructions? Why or why
not?
-
If the Java compiler accepts these instructions, what output would you
expect to see when you run the program?
-
Check your answers to a and b experimentally.
Basic Autoboxing and Unboxing
-
These examples illustrate the mixing of primitive int variables
with objects from the wrapper class Integer. Oracle's Java
Tutorial
on Autoboxing
and Unboxing provides some basic background.
Consider the following instructions.
System.out.println("square(littlei): " + square(littlei));
System.out.println("sqr(bigi): " + sqr(bigi));
System.out.println();
-
Why do you think the Java compiler allows these instructions?
-
How is it possible for an int to be passed to square
which expects an Integer?
-
How is it possible for an Integer to be passed to sqr
which expects an int?
-
Review the definition
of Java's
Integer class. What code do you think the Java compiler inserts when
an int is passed to square?
-
Again reviewing the definition of
of Java's
Integer class, what code you do think the Java compiler
inserts when an Integer is passed to sqr?
-
With this background on autoboxing and unboxing, consider the following procedure.
/**
* Square an Integer, using boxing/unboxing.
*/
public static Integer
sq(Integer x)
{
return x * x;
} // sq(Integer)
Consider also the following instructions, which will get added to main.
System.out.println("sq(bigi): " + sq(bigi));
System.out.println("sq(littlei): " + sq(littlei));
System.out.println();
-
Do you expect the Java compiler to accept this new procedure and the
corresponding instructions? Why or why not?
-
If the Java compiler accepts these instructions, how do you think the Java
compiler is interpreting the statement return x * x? That is,
using the definition of
of Java's
Integer class, what code do you think the Java compiler is
adding behind the scenes?
Boxing and Arrays
The past examples illustrate how autoboxing and unboxing allows a Java
compiler to automatically convert between Java's primitive types
(e.g., int) and the corresponding wrapper classes
(e.g., Integer). The next experiments explore arrays of
primitives and the corresponding wrapper classes.
-
Consider the following instructions.
System.out.println("littleSum(bigvals): " + littleSum(bigvals));
System.out.println("bigSum(littlevals): " + bigSum(littlevals));
System.out.println();
-
Do you expect the Java compiler to accept these instructions? Why or why
not?
-
If the Java compiler accepts these instructions, what output would you
expect to see when you run the program?
-
Check your answers to a and b experimentally.
-
What, if anything, does this exercise suggest about autoboxing/unboxing or
related issues?
What about null?
The readings note that one potential issue with autoboxing and unboxing is that we
have to deal with null as a special case.
-
As a first experiment with a null value, consider the following
instructions, in which a null is used in a function designed to square
an Integer object.
Integer ex8 = null;
System.out.println("square(ex8): " + square(ex8));
System.out.println();
-
Do you expect the Java compiler to accept these instructions? Why or why not?
-
If the Java compiler accepts these instructions, what output would you
expect to see when you run the program?
-
Check your answers to a and b experimentally.
-
What, if anything, does this exercise suggest about autoboxing/unboxing or
related issues?
-
Next consider the following instructions, in which a null is passed for
a String object.
String ex9 = null;
System.out.println("bracket(ex9): " + bracket(ex9));
System.out.println();
-
Do you expect the Java compiler to accept these instructions? Why or why not?
-
If the Java compiler accepts these instructions, what output would you
expect to see when you run the program?
-
Check your answers to a and b experimentally.
-
What, if anything, does this exercise suggest about autoboxing/unboxing or
related issues?
For another experiment with a null value, consider the following
instructions, in which a null is used for an array of objects.
String ex10 = null;
System.out.println("parenthesize(ex10): " + parenthesize(ex10));
System.out.println();
-
Do you expect the Java compiler to accept these instructions? Why or why not?
-
If the Java compiler accepts these instructions, what output would you
expect to see when you run the program?
-
Check your answers to a and b experimentally.
-
What, if anything, does this exercise suggest about autoboxing/unboxing or
related issues?
Immutable Objects
Some Java objects are immutable — once created, they cannot be
changed. The following readings provide some basic background:
-
Review the specifications
for Java's
Integer class.
-
What methods are available to change the value of an Integer
object?
-
Back in Step1, code included the following
Integer integer1 = new Integer (2)
integer1 += 5;
Interpret the second line, now that you know that Integer objects
are immutable. What code do you think the compiler inserts behind the
scenes to make this code work?
-
Review the specifications
for Java's
String class.
-
What methods are available to change the value of an String
object?
-
Various methods within the String class return substrings, change
a character of a string, or otherwise produce a modification of the
original String object. Do any of these methods change the
original object, or do they always create a new object? Explain briefly.
This document is available on the World Wide Web as
http://www.walker.cs.grinnell.edu/courses/207.sp15/labs/lab-references-boxing.shtml