3.2 Creating Objects
Key terms: constructor, canonical name, simple name, import statement, convenience method, refactor, factory method
3.2.1 Constructors
While String objects are automatically created from string literals, all other objects are created
with the new operator and initialized by a special class member called a constructor.
Constructors are similar to methods: they are sequences of instructions and may take arguments.
Every constructor, however, has a fixed name—the name of its class—and its sole purpose is to
initialize a newly allocated object. Constructors can be overloaded for different forms of
initialization.
Each explicit creation of an object in Listing 3.2.1 follows the same pattern at runtime: new
allocates memory for the object, the specified constructor is executed, and a reference to the
object is returned.
Listing 3.2.1 - ConstructorDemo.java
package chap03.sect2;
import java.math.BigInteger;
import java.util.BitSet;
import java.util.Properties;
/**
* Demonstrates the use of the new operator to create objects and constructors to initialize them.
*
* @author Drue Coles
*/
public class ConstructorDemo {
public static void main(String[] args) {
BigInteger val = new BigInteger("100000000001");
System.out.println(val.pow(2));
BitSet b1 = new BitSet(10);
b1.set(1); // -1--------
b1.set(5, 9); // -1---1111-
b1.flip(3, 7); // -1-11--11-
System.out.println(b1);
Properties creature = new Properties();
creature.setProperty("common name", "quoll");
creature.setProperty("kingdom", "Animalia");
creature.setProperty("phylum", "Chordata");
creature.setProperty("class", "Mammalia");
System.out.println(creature.getProperty("common name"));
}
}
Output 3.2.1
10000000000200000000001
{1, 3, 4, 7, 8}
quoll
The BigInteger class represents integers with arbitrarily many digits. It will be introduced more
fully later in the chapter and used in examples throughout the book. Here, an instance is created by
passing a string of digits to the constructor. The expression val.pow(2) produces a new
BigInteger whose value is the square of the integer modeled by val.
BitSet stores on/off flags using a compact internal representation. The class also provides
methods to combine and modify bit sets, producing results based on the logical relationships between
the flags in each set. An instance of this class could be used, for example, to track which users of
an online service are currently logged in.
The Properties class stores a collection of key-value pairs of strings. In the listing, several
pairs are added with setProperty, and one value is retrieved and displayed with getProperty.
3.2.2 The toString Method
The program outputs instances of BigInteger, BitSet, and Properties the same way it outputs
strings and primitive values—by passing them to println. This may seem to imply that there is an
overload of println for each of these types, but instead there is a single version that accepts an
object of any type, converts it to a string, and outputs the string.
But how does println convert an arbitrary object to a string? Every object has a toString method
for this purpose, which returns a text description of the object's current state.
The compiler also converts an object to a string when needed for string concatenation. For example:
BigInteger avConstant = new BigInteger("602214076000000000000000");
System.out.println("Avogadro's constant: " + avConstant);
The left operand of + is a string, so the right operand must also be a string. The compiler
inserts a call to avConstant.toString() for this purpose.
The toString method can also be called directly, as shown in the following code fragment:
// display last 10 digits
String digits = bigInteger.toString();
int n = digits.length();
System.out.println(digits.substring(n - 10));
3.2.3 Import Statements
The BigInteger class is defined in the java.math package. The full name of a class, which
includes its package, is called its canonical name. The abbreviated name without the package is
the simple name. Some classes in the Java API share a simple name but reside in different
packages, so they are distinguished by their canonical names; for example, java.sql.Date and
java.util.Date.
Writing canonical names throughout a program would be cumbersome. In Listing 3.2.1, only simple
names appear. This is legal because of the import statements near the top of the file. An
import statement tells the compiler that a given simple name refers to a specified canonical
name. For example, we can write BigInteger because an import statement maps that simple name to
java.math.BigInteger.
You may have noticed that we used String and System without import statements. These classes
belong to the java.lang package, whose classes are implicitly imported in every Java source file.
3.2.4 StringBuilders
The StringBuilder class models a mutable sequence of characters. Unlike strings, StringBuilder
objects are created with the new operator and initialized by a constructor.
In Listing 3.2.4, characters in a StringBuilder are replaced and reversed. The program's output
confirms that the objects themselves are modified by the mutators.
Listing 3.2.4 - StringBuilderDemo.java
package chap03.sect2;
/**
* Demonstrates the use of StringBuilders for mutable character sequences.
*
* @author Drue Coles
*/
public class StringBuilderDemo {
public static void main(String[] args) {
StringBuilder country = new StringBuilder("FINLAND");
System.out.println(country);
country.replace(0, 3, "ICE"); // mutator
System.out.println(country);
StringBuilder word = new StringBuilder("GATEMAN");
System.out.println(word);
word.reverse(); // mutator
System.out.println(word);
}
}
Output 3.2.4
FINLAND
ICELAND
GATEMAN
NAMETAG
StringBuilder also provides convenience methods for insertion and deletion. A
convenience method is a shortcut to existing functionality — it provides a simpler or more
intuitive way to perform a task that could be done with other methods. For example, inserting and
deleting characters could be done through replacements.
Whatever can be done with StringBuilder objects can also be done indirectly with strings. Strings
cannot be changed, but new strings can be created and combined to bring about the same effect. This
is illustrated by the following two code fragments, which produce the same output:
StringBuilder country = new StringBuilder("FINLAND");
country.replace(0, 3, "ICE");
System.out.println(country); // ICELAND
String country = "FINLAND";
country = "ICE" + country.substring(3);
System.out.println(country); // ICELAND
Strings are convenient for construction, concatenation, and general text processing. When a sequence
of edits is required, however, StringBuilder objects can simplify the code.
StringBuilder objects can also be more efficient. Because strings are immutable, repeated
modifications create temporary objects, increasing runtime overhead.
This book emphasizes simplicity over runtime efficiency, so strings are generally used. It is worth
noting, however, that IDEs often suggest refactoring blocks of code with repeated string
concatenations to use a StringBuilder instead. Refactoring is the process of restructuring
code without changing its behavior.
3.2.5 Factory Methods
A factory method is a static method that provides an object of its class to client code. It may create a new object and initialize it with a constructor call, or it may return a reference to an existing object. Classes sometimes offer factory methods in addition to, or instead of, constructors for several reasons, including:
-
They can have descriptive names that clarify the purpose or configuration of the object.
-
Differently named factory methods can provide different forms of initialization for the same arguments, which is not possible for constructors since their name is fixed, and overloads must have different numbers or types of arguments.
-
When an object can safely be shared across an application, factory methods can return a reference to the same instance instead of creating a new one.
In Listing 3.2.5, System.out.printf (f is for format) outputs currency symbols and dates. It
formats strings containing various types of data in the same way as String.format (Section 3.1.3).
The %n at the end of the format string is an escape sequence for a line separator. While \n
usually works, the correct encoding of a line separator is platform-dependent. However, printf and
String.format replace %n with the correct platform line separator (probably \n or \r\n).
Listing 3.2.5 - FactoryMethodDemo.java
package chap03.sect2;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Currency;
/**
* Demonstrates the use of factory methods to create Currency and LocalDate objects.
*
* @author Drue Coles
*/
public class FactoryMethodDemo {
public static void main(String[] args) {
// display four currency symbols
String eur = Currency.getInstance("EUR").getSymbol(); // euro
String gbp = Currency.getInstance("GBP").getSymbol(); // pound
String jpy = Currency.getInstance("JPY").getSymbol(); // yen
String usd = Currency.getInstance("USD").getSymbol(); // dollar
System.out.printf("Currency symbols: %s %s %s %s %n", eur, gbp, jpy, usd);
// display a historical date and today's date
LocalDate apollo11 = LocalDate.of(1969, 7, 20);
LocalDate today = LocalDate.now();
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("EEEE, MMMM d, uuuu");
System.out.printf("First moon landing: %s %n", apollo11.format(fmt));
System.out.printf("Today: %s %n", today.format(fmt));
}
}
Output 3.2.5
Currency symbols: € £ ¥ $
First moon landing: Sunday, July 20, 1969
Today: Friday, November 28, 2025
The Currency.getInstance factory method accepts a standard ISO 4217 currency code (like USD) and
returns a Currency object. Because the class is immutable, the method can cache commonly used
instances. The LocalDate.of factory method returns an instance representing a specified date, and
LocalDate.now returns one for the current date according to the system clock.
Consider the following alternative code for outputting a date:
LocalDate apollo11 = LocalDate.of(1969, 7, 20);
System.out.printf("First moon landing: " + apollo11);
Output
First moon landing: 1969-07-20
The implicit invocation of toString on apollo11 produces a result in YYYY-M-D format. In Listing
3.2.5, a DateTimeFormatter is used instead to produce a custom format. The factory method
DateTimeFormatter.ofPattern takes a pattern string and returns an object whose format method
converts a LocalDate (or any other java.time date-time type) into a string following that
pattern.