A generic factory creates objects through a type-parameterized contract, so callers receive a specific compile-time type without depending on a concrete implementation. In Java, the pattern is usually an interface such as Factory<T>, a generic method that accepts a type token, or both. The right design depends on whether the implementation is fixed, selected at runtime, cached, or configured.
What a generic factory is
A generic factory puts object creation behind an API whose product type is represented by T. The type parameter appears in the factory contract and in the method return type, allowing the compiler to check that a factory produces the type its callers expect.
interface Factory<T> {
T create();
}
final class Report {
}
final class ReportFactory implements Factory<Report> {
@Override
public Report create() {
return new Report();
}
}
Factory<Report> factory = new ReportFactory();
Report report = factory.create();
The caller programs to Factory<Report>, not to the construction details inside ReportFactory. Oracle describes generic types as classes or interfaces parameterized over types, and the Java compiler performs type checking on those parameterized uses. The diamond operator can also infer constructor type arguments when you instantiate a generic class.
Two common designs
A parameterized factory object
Use a Factory<T> implementation when creation has state, configuration, dependencies, or a lifecycle policy.
interface Factory<T> {
T create();
}
final class ParserFactory implements Factory<DocumentParser> {
private final ParserOptions options;
ParserFactory(ParserOptions options) {
this.options = options;
}
@Override
public DocumentParser create() {
return new DocumentParser(options);
}
}
A factory can return an interface or subclass, choose an implementation from configuration, reuse an instance, or coordinate synchronization. Java APIs use this style of abstraction in classes such as SocketFactory and DocumentBuilderFactory; the concrete implementation may depend on the environment or provider.
A generic factory method
A generic method is convenient when the caller supplies both the requested type and the construction behavior.
import java.util.function.Supplier;
static <T> T create(Class<T> type, Supplier<? extends T> supplier) {
return supplier.get();
}
Report report = create(Report.class, Report::new);
Class<T> is a type token: it carries runtime class information that Java’s erased generic type parameter does not normally retain. The supplier is a producer, so Supplier<? extends T> permits a supplier of T or of a subtype of T>. In this example the type parameter is useful for preserving and validating the requested type; the supplier still supplies the actual construction behavior.
Why use a factory instead of a constructor?
| Concern | Direct constructor | Factory |
|---|---|---|
| Coupling | Exposes a concrete class and its constructor. | Can return an interface or subclass. |
| Lifecycle | Normally creates a new object for each call. | Can cache, reuse, pool, or otherwise manage instances. |
| Runtime choice | Choice is usually hard-coded at the call site. | Can select from configuration, a registry, an enum, or another key. |
| Type safety | Strong when the constructor type is known. | Generic return types preserve checks across an abstraction; raw types and casts weaken them. |
| Discoverability | Constructor syntax is familiar. | A named method can express intent, but callers must learn its name. |
Prefer a constructor when there is one obvious implementation and no selection or lifecycle policy. Introduce a factory when construction policy is likely to change, callers should depend on an interface, or creation requires environment-specific coordination.
Rank #2
Returning the right generic type
Put T in the return type
The compiler can infer a method’s type parameter from its arguments and target type only when the signature exposes that relationship.
static <T> T create(Class<T> type, Supplier<? extends T> supplier) {
return supplier.get();
}
Invoice invoice = create(Invoice.class, Invoice::new);
A method returning Object loses this relationship and forces every caller to cast. A raw Factory loses it even earlier:
// Avoid:
Factory raw = new ReportFactory();
Report report = (Report) raw.create();
Oracle warns that raw types bypass generic checks and defer failures until runtime. Use Factory<Report> instead.
Use bounded wildcards for producers
If a factory only produces values, ? extends T expresses that a subtype is acceptable:
Outdated Drivers Are Slowing You Down
One free scan finds every outdated or missing driver and matches the right update for your exact hardware.Free scan · exact hardware matchPC Slower Than It Used to Be?
A free scan shows the junk files, broken settings and background clutter dragging Windows down - then fixes them in one click.Free scan · Windows 10 & 11static <T> List<T> collect(Supplier<? extends T> supplier, int count) {
List<T> result = new ArrayList<>();
for (int i = 0; i < count; i++) {
result.add(supplier.get());
}
return result;
}
Do not add wildcards mechanically. Use them where variance reflects the operation; a factory that both consumes and produces a type often needs an exact T instead.
Erasure: what a generic factory cannot know
Java implements generics through erasure. Oracle states that the compiler removes each type parameter and replaces it with its first bound, or with Object when the parameter is unbounded. Consequently, Java cannot instantiate an arbitrary erased type variable with code such as new T().
// Does not compile:
static <T> T create() {
return new T();
}
When runtime selection is required, provide information that survives erasure:
- A
Class<T>token. - An enum or other explicit key.
- A registry mapping keys to typed factories.
- A
Supplier<? extends T>or another construction strategy.
Bridge methods generated by the compiler preserve polymorphism after erasure, but they do not restore type arguments as runtime data.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Rank #4
Keeping runtime selection type-safe
A registry should make its key-to-product relationship explicit rather than returning Object for every lookup.
enum Format {
JSON, XML
}
final class FormatFactories {
private final Map<Format, Factory<? extends Document>> factories = Map.of(
Format.JSON, JsonDocument::new,
Format.XML, XmlDocument::new
);
Document create(Format format) {
Factory<? extends Document> factory = factories.get(format);
if (factory == null) {
throw new IllegalArgumentException("Unsupported format: " + format);
}
return factory.create();
}
}
The return type is the common abstraction, Document. If an API must return an exact subtype selected by a runtime key, the key and registry need a stronger typed association, often through a dedicated typed key class or separate methods.
How to handle an unavoidable unchecked cast
Some adapters sit between an erased or external API and a typed API. Keep the cast in one small method, validate the runtime class, and expose only the checked generic surface.
static <T> T checked(Object value, Class<T> type) {
return type.cast(value);
}
Class.cast performs a runtime check and throws ClassCastException at the boundary instead of spreading unchecked casts through callers. If a cast cannot be validated, do not disguise it with @SuppressWarnings("unchecked"); redesign the key, registry, or factory contract.
Free tools Windows power users keep installed
One-click scans. No signup required.
Best Value
Generic factory, static factory method, and Factory Method pattern
| Term | Meaning | Typical example |
|---|---|---|
| Generic factory | A type-safe API whose factory class or method is parameterized with T. |
Factory<Report> or <T> T create(...) |
| Static factory method | Any named static method that returns an instance; it may or may not be generic. | DocumentBuilderFactory.newInstance() |
| GoF Factory Method | An overridable creation method in a creator hierarchy, allowing concrete creators to choose the product class. | A subclass overriding a creation operation |
These categories can overlap, but they are not synonyms. The Effective Java discussion by Joshua Bloch explicitly distinguishes a static factory method from the Factory Method pattern. DocumentBuilderFactory.newInstance() hides provider selection through a static API; it is not automatically a GoF Factory Method merely because it is called a factory.
Design checklist
- Use
Factory<T>when the factory object has configuration, dependencies, or lifecycle state. - Use a generic method when the caller can supply a type token and construction strategy.
- Expose the most specific useful interface type rather than
Object. - Pass a
Class<T>, explicit key, registry, or supplier when runtime information is needed. - Use
? extends Tfor producer inputs where subtype production is intentional. - Keep any unavoidable unchecked operation inside one validated adapter.
- Choose a constructor when there is one clear implementation and no policy to hide.
Frequently Asked Questions
Can a Java generic factory call new T()?
No. Type erasure removes the type argument needed for that construction. Pass a Class<T>, supplier, registry, or explicit key instead.
Why not return Object from a factory?
It discards compile-time type information and forces callers to cast. A parameterized return type lets the compiler detect mismatches earlier.
Is every static factory method a Factory Method pattern?
No. A static factory method is a named static creator; the GoF Factory Method is an overridable creation operation in a creator hierarchy.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

