Mastering Java Constructors and Design Patterns: From Implicit to Singleton
This article provides a comprehensive guide to advanced Java concepts, covering implicit, no‑arg, and argument constructors, initialization blocks, static initialization, default value guarantees, visibility rules, garbage collection, finalizers, and common construction patterns such as singleton, helper, factory, and dependency injection, helping developers deepen their object‑oriented mastery.
Java, invented by Sun Microsystems and released in 1995, is one of the most widely used programming languages. It is a general‑purpose language with powerful libraries, a runtime, simple syntax, platform independence (Write Once, Run Anywhere), and a vibrant community.
This series assumes basic Java knowledge and aims to elevate your skills with advanced concepts, using Java 7 and Java 8 syntax.
1. Introduction
Java is an object‑oriented language, making instance creation a core concept. Constructors play a central role, and Java offers many ways to define them.
2. Instance Construction
2.1 Implicit Constructor
Even if a class declares no constructor, the compiler generates an implicit one that is invoked when using new.
package com.javacodegeeks.advanced.construction;
public class NoConstructor {
}Creating an instance:
final NoConstructor noConstructorInstance = new NoConstructor();2.2 No‑Arg Constructor
A no‑arg constructor is the simplest explicit constructor.
package com.javacodegeeks.advanced.construction;
public class NoArgConstructor {
public NoArgConstructor() {
// Constructor body here
}
}Creating an instance:
final NoArgConstructor noArgConstructor = new NoArgConstructor();2.3 Constructor with Arguments
Argument constructors allow parameterized object creation.
package com.javacodegeeks.advanced.construction;
public class ConstructorWithArguments {
public ConstructorWithArguments(final String arg1, final String arg2) {
// Constructor body here
}
}Creating an instance requires both arguments:
final ConstructorWithArguments constructorWithArguments = new ConstructorWithArguments("arg1", "arg2");Constructors can call each other using this, reducing code duplication.
public ConstructorWithArguments(final String arg1) {
this(arg1, null);
}2.4 Initialization Blocks
Java also supports instance initialization blocks, which run before any constructor.
package com.javacodegeeks.advanced.construction;
public class InitializationBlock {
{
// initialization code here
}
}Multiple blocks execute in the order they appear.
package com.javacodegeeks.advanced.construction;
public class InitializationBlocks {
{
// block 1
}
{
// block 2
}
}Blocks are not a replacement for constructors but run before them.
package com.javacodegeeks.advanced.construction;
public class InitializationBlockAndConstructor {
{
// initialization code here
}
public InitializationBlockAndConstructor() {
}
}2.5 Construction Guarantee
Java automatically initializes fields to default values (e.g., false, 0, null).
package com.javacodegeeks.advanced.construction;
public class InitializationWithDefaults {
private boolean booleanMember;
private byte byteMember;
private short shortMember;
private int intMember;
private long longMember;
private char charMember;
private float floatMember;
private double doubleMember;
private Object referenceMember;
public InitializationWithDefaults() {
System.out.println("booleanMember = " + booleanMember);
System.out.println("byteMember = " + byteMember);
System.out.println("shortMember = " + shortMember);
System.out.println("intMember = " + intMember);
System.out.println("longMember = " + longMember);
System.out.println("charMember = " + charMember);
System.out.println("floatMember = " + floatMember);
System.out.println("doubleMember = " + doubleMember);
System.out.println("referenceMember = " + referenceMember);
}
}Instantiating prints the default values.
final InitializationWithDefaults initializationWithDefaults = new InitializationWithDefaults();2.6 Visibility
Constructors follow Java’s visibility rules and can have access modifiers to control who can instantiate a class.
2.7 Garbage Collection
The JVM automatically reclaims memory of objects that are no longer reachable. Object allocation is cheap, but creating many long‑lived objects can fill the old generation and trigger costly stop‑the‑world collections.
2.8 Finalizers
Finalizers are similar to destructors but are generally discouraged. Since Java 7, try‑with‑resources and the AutoCloseable interface provide a safer alternative.
try (final InputStream in = Files.newInputStream(path)) {
// code here
}3. Static Initialization
Static initialization blocks run once when the class is first loaded.
package com.javacodegeeks.advanced.construction;
public class StaticInitializationBlock {
static {
// static initialization code here
}
}Multiple static blocks execute in declaration order and are thread‑safe.
package com.javacodegeeks.advanced.construction;
public class StaticInitializationBlocks {
static {
// block 1
}
static {
// block 2
}
}4. Construction Patterns
4.1 Singleton
The naive singleton is not thread‑safe.
package com.javacodegeeks.advanced.construction.patterns;
public class NaiveSingleton {
private static NaiveSingleton instance;
private NaiveSingleton() {}
public static NaiveSingleton getInstance() {
if (instance == null) {
instance = new NaiveSingleton();
}
return instance;
}
}Eager singleton uses a static final instance.
package com.javacodegeeks.advanced.construction.patterns;
public class EagerSingleton {
private static final EagerSingleton instance = new EagerSingleton();
private EagerSingleton() {}
public static EagerSingleton getInstance() {
return instance;
}
}Lazy singleton adds synchronized access, which may reduce concurrency.
package com.javacodegeeks.advanced.construction.patterns;
public class LazySingleton {
private static LazySingleton instance;
private LazySingleton() {}
public static synchronized LazySingleton getInstance() {
if (instance == null) {
instance = new LazySingleton();
}
return instance;
}
}Modern practice prefers dependency injection over singletons.
4.2 Utility/Helper Classes
Helper classes are non‑instantiable containers of static methods.
package com.javacodegeeks.advanced.construction.patterns;
public final class HelperClass {
private HelperClass() {}
public static void helperMethod1() {
// Method body here
}
public static void helperMethod2() {
// Method body here
}
}4.3 Factory Pattern
Factories encapsulate object creation.
package com.javacodegeeks.advanced.construction.patterns;
public class Book {
private Book(final String title) {}
public static Book newBook(final String title) {
return new Book(title);
}
}Using an interface for abstract factories:
public interface BookFactory {
Book newBook();
}
public class Library implements BookFactory {
@Override
public Book newBook() {
return new PaperBook();
}
}
public class KindleLibrary implements BookFactory {
@Override
public Book newBook() {
return new KindleBook();
}
}4.4 Dependency Injection
Dependencies should be supplied externally, typically via constructors.
package com.javacodegeeks.advanced.construction.patterns;
import java.text.DateFormat;
import java.util.Date;
public class Dependant {
private final DateFormat format;
public Dependant(final DateFormat format) {
this.format = format;
}
public String format(final Date date) {
return format.format(date);
}
}This approach makes the class easier to test and more flexible.
The article has covered various ways to construct and initialize Java objects, including several widely used patterns. The next part will explore the Object class and its common methods such as equals, hashCode, toString, and clone.
Programmer DD
A tinkering programmer and author of "Spring Cloud Microservices in Action"
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
