Object Instantiation Techniques
Five primary methods exist for Java object creation:
1. new Keyword
The new operator invokes constructors directly. Pros: Simple syntax and high efficiency. Cons: Requires compile-time type knowledge.
public class Widget {
public static void main(String[] args) {
Widget instance = new Widget();
}
}
2. Reflection API
Reflection enables runtime class loading. Pros: Dynamic instantiation. Cons: Performance overhead and exception handling.
public class Gadget {
public Gadget() {
// Initialization logic
}
}
try {
Gadget refObj = Gadget.class.getDeclaredConstructor().newInstance();
} catch (Exception e) {
e.printStackTrace();
}
3. clone() Method
Object cloning avoids constructors. Pros: Bypasses initializatoin logic. Cons: Requires Cloneable implementation and careful deep-copy handling.
public class Item implements Cloneable {
private String data;
public Item(String data) {
this.data = data;
}
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
Item original = new Item("Cloned Data");
Item replica = (Item) original.clone();
4. Deserialization
Object resurrection via serialization. Pros: State preservation. Cons: Performance impact and Serializable requirement.
public class Entity implements Serializable {
private static final long serialVersionUID = 1L;
private String content;
public Entity(String content) {
this.content = content;
}
public static void main(String[] args) {
Entity source = new Entity("Serialized");
try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("entity.ser"))) {
out.writeObject(source);
} catch (IOException e) {
e.printStackTrace();
}
}
}
5. Third-Party Libraries
Tools like Objenesis bypass constructors. Pros: Flexible initialization. Cons: External dependencies.
public class Component {
private String value;
public Component() {
this.value = "Objenesis";
}
}
Objenesis objenesis = new ObjenesisStd();
ObjectInstantiator<Component> factory = objenesis.getInstantiatorOf(Component.class);
Component obj = factory.newInstance();
Object Creation Mechanism
Bytecode sequence for object creation:
public class CreationDemo {
public static void main(String[] args) {
Object item = new Object();
}
}
newinstruction allocates heap memorydupduplicates reference on operand stackinvokespecialcalls<init>constructorastore_1stores reference in local variable
Object Creation Process
- Class Verifciation: Check class loading status in Metaspace
- Memory Allocation:
- Pointer bumping (compact heaps)
- Free lists (fragmented heaps)
- Concurrency Handling:
- CAS with retry
- TLAB allocation
- Memory Initialization: Default value assignment
- Header Setup: Storing metadata in object header
- Constructor Execution: Custom initialization via
init
Object Structure Analysis
Using JOL for object layout inspection:
<dependency>
<groupId>org.openjdk.jol</groupId>
<artifactId>jol-core</artifactId>
<version>0.9</version>
</dependency>
public class LayoutInspector {
public static void main(String[] args) {
Simple obj = new Simple();
System.out.println(ClassLayout.parseInstance(obj).toPrintable());
}
}
class Simple {}
Typical output reveals:
- 12-byte header (64-bit JVM with compressed pointers)
- Instance data fields
- Alignment padding
Object Header Components
Header comprises:
- Mark Word: 64-bit field containing:
- Hash code
- GC age
- Lock flags
- Klass Pointer: Type metadata reference
Mark Word structure varies by object state:
| State | Mark Word Format |
|---|---|
| Unlocked | unused:25 | hash:31 | unused:1 | age:4 | biased_lock:1 | lock:01 |
| Biased | thread:54 | epoch:2 | unused:1 | age:4 | biased_lock:1 | lock:01 |
| Lightweight Lock | lock_record_ptr:62 | lock:00 |
| Heavyweight Lock | monitor_ptr:62 | lock:10 |
| Marked for GC | lock:11 |
Instance Data Layout
Field arrangement follows:
- Grouping by field width
- Superclass fields precede subclass
- Field compaction with
-XX:+CompactFields
Padding Alignment
8-byte boundary enforcement may add filler bytes.
Object Access Methods
Two primary reference models:
Handle-Based Access
Reference points to handle pool entry containing:
- Instance data pointer
- Type metadata pointer
Direct Pointer Access
Reference directly points to heap object containing embedded type pointer.
Object Finalization Process
The finalize() method provides cleanup hooks:
public class ResourceHolder {
@Override
protected void finalize() throws Throwable {
try {
// Resource release logic
} finally {
super.finalize();
}
}
}
Key considerations:
- Single invocation guarantee
- Resurrection capability during execution
- GC state transitions: reachable → resurrectable → unreachable
Resurrection demonstration:
public class ResurrectionDemo {
static ResurrectionDemo holder;
@Override
protected void finalize() {
holder = this; // Resurrection
}
public static void main(String[] args) throws InterruptedException {
holder = new ResurrectionDemo();
holder = null;
System.gc();
Thread.sleep(1000);
System.out.println(holder == null ? "Collected" : "Resurrected");
}
}