A static method belongs to the class itself — you call it without creating an instance. An instance method belongs to an object created from the class, and it can read and modify that object’s fields via this. The choice between them is mostly about whether the method needs per-instance state to do its job.
Side-by-side
public class AccountService {
private Account context;
// Constructor — only runs when instantiating
public AccountService(Account a) {
this.context = a;
}
// Instance method — needs the constructor-provided context
public Boolean isHighValue() {
return this.context.AnnualRevenue > 10000000;
}
// Static method — doesn't need state; works on whatever you pass in
public static List<Account> findByIndustry(String industry) {
return [SELECT Id, Name FROM Account WHERE Industry = :industry];
}
}
// Calling them
List<Account> tech = AccountService.findByIndustry('Technology'); // static — no instance
AccountService svc = new AccountService(someAccount);
Boolean hv = svc.isHighValue(); // instance — needs svc
Comparison
| Aspect | Static method | Instance method |
|---|---|---|
| Belongs to | The class | An object |
| Called via | ClassName.method() | instance.method() |
Can access this? | No | Yes |
| Can read instance fields? | No (only static fields) | Yes |
| Can read static fields? | Yes | Yes |
| Overridable in subclass? | No (hidden, not overridden) | Yes, if declared virtual |
| Memory model | One copy per class, lives for the transaction | One per object instance |
| Typical use | Utility functions, factories, service operations | Domain models with internal state |
When to use static
Static methods are the right call when:
- The method is a pure function — same inputs always produce the same output.
- It doesn’t need to remember anything between calls.
- You’re building a utility class (
StringUtil,DateUtil,Validator). - It’s a service-layer entry point — many
@AuraEnabledcontroller methods are static because each call is independent. - It’s a factory method that constructs and returns instances.
public class OrderUtil {
public static Decimal calculateTax(Decimal subtotal, String region) {
// No state needed — given the same inputs, returns the same result
return subtotal * getTaxRate(region);
}
private static Decimal getTaxRate(String region) { /* ... */ return 0; }
}
When to use instance
Instance methods are the right call when:
- The object has state that callers can configure via constructor or setters, and methods operate on that state.
- You’re modelling a domain object (a wrapper around an Account, an order processor with internal state).
- You need polymorphism — different subclasses provide different behaviours for the same method.
public virtual class PriceCalculator {
protected Decimal basePrice;
public PriceCalculator(Decimal basePrice) {
this.basePrice = basePrice;
}
public virtual Decimal calculate() {
return basePrice;
}
}
public class DiscountedCalculator extends PriceCalculator {
private Decimal discountPct;
public DiscountedCalculator(Decimal basePrice, Decimal discountPct) {
super(basePrice);
this.discountPct = discountPct;
}
public override Decimal calculate() {
return basePrice * (1 - discountPct);
}
}
You cannot do that with static methods — static methods cannot be overrided.
Static state survives the transaction
A critical subtlety: static fields persist for the lifetime of the transaction, not just one method call. Two methods in the same call stack share static state. This is how recursion guards in trigger handlers usually work:
public class TriggerHandler {
private static Boolean alreadyRan = false;
public static void handle(List<Account> accounts) {
if (alreadyRan) return;
alreadyRan = true;
// ... do work that might cause recursion ...
}
}
Once the transaction ends, all static state is discarded. The next transaction starts fresh. This is not a cache across transactions — that needs Platform Cache or a @AuraEnabled(cacheable=true) method.
Performance note
There’s a small overhead in instantiating a class — running the constructor, allocating heap. For a pure utility method called thousands of times in a loop, static is marginally faster. In practice this is negligible compared to a single SOQL query, so don’t pick static for performance; pick it because the method genuinely has no state.
What interviewers are really looking for
Naming the difference is the cheap answer. Senior signal: explain that static state lives for the transaction, that instance methods enable polymorphism via virtual/override, and that the choice is driven by whether the method needs state, not by performance. Mention the trigger-recursion-guard pattern as a real-world use of static fields, and you’ve shown design experience.
Verified against: Apex Developer Guide — Static and Instance Methods, Variables, and Initialization Code. Last reviewed 2026-05-17 for Spring ‘26 release.