11

I've read in the Apex Workbook and the Apex Developer Guide the mention of inner classes. What is their purpose?

I see in the Apex Workbook that they used private variables and setter/getter methods in the inner class, but why didn't they just do that in the outer class with a constructer, getter, and setter?

0

2 Answers 2

21

I think this question is way too broad for one answer to cover. I suggest you look at some libraries out there to see how they use inner classes.

There are so many use cases. It would be really difficult to cover them all. But I will just cover three here:

  • Generalization (DRY)
  • Selection Wrappers
  • Deserialization

Generalization (DRY)

I know for my DML library, I use a few, all of which have their behavior defined by interfaces. But that is neither here nor there.

Maybe a concrete example will help you better understand. Take a look at the GenericResult inner class in my DMLResults class.

public class GenericResult
{
    final Id recordId;
    final List<Database.Error> errors;
    public GenericResult(Id recordId, List<Database.Error> errors)
    {
        this.recordId = recordId;
        this.errors = (errors != null) ? errors : new List<Database.Error>();
    }
    public Id getId() { return recordId; }
    public List<Database.Error> getErrors() { return errors; }
}

This class helps me out with DRY programming by letting me use one class to represent all of the *Result system classes (see also: Do the *Result objects in Database have a common ancestor?). Because of this implementation, my PartialResult logic can use GenericResult instances once instead of repeating the logic once each for SaveResult, UpsertResult, DeleteResult, etc.


Selection Wrappers

Often wrapper classes are often used for record selection on a Visualforce Page. This can be as simple as:

public class MyObjectWrapper
{
    public Boolean isSelected { get; set; }
    public MyObject__c record { get; private set; }
    public MyObjectWrapper(MyObject__c record)
    {
        this.record = record;
        this.isSelected = false;
    }
}

Then in your markup, you would see something like:

<apex:repeat value="{!wrappers}" var="wrapper">
    <apex:inputCheckbox value="{!wrapper.isSelected}">
    <!--other output-->
</apex:repeat>

Deserialization

Deserialization is much simpler using an inner class, though you can use top-level classes as well.

public class TopLevel
{
    public class SomeStructure
    {
        public String someProperty;
    }
}

Then you can deserialize using this class like:

SomeStructure data = JSON.deserialize(
    '{"someProperty": "<value>"}',
    TopLevel.SomeStructure.class
);
2
  • Is a constructer considered a inner class?
    – Tyler Zika
    Commented Aug 25, 2016 at 22:13
  • 1
    @Tyler No, every class has a constructor, whether it is an inner class or top-level. They start off with an implicit 0-parameter constructor. You can define additional constructors, and as soon as you start doing that, you lose the implicit constructor. See Using Constructors.
    – Adrian Larson
    Commented Aug 25, 2016 at 22:15
14

Their primary use in my experience is to logically group classes together and/or reduce the number of top-level classes. This starts to matter when your code base grows into hundreds of top-level classes.

Some inner class examples are:

  • Multiple public implementations of an interface
  • Variations on a theme e.g. a series of map-like public classes for various primitive types
  • Private builder/fixture classes used in the various methods of a test class
  • There are multiple platform APIs, e.g. Dom.XmlNode, that provide examples

The outer class behaves like a namespace (as Java-style namespaces don't exist in Apex).

Note that (frustratingly) inner classes can't be used in a few places e.g. as a type for an apex:attribute. But generally they are pretty much interchangeable with top level classes.

(Note that the ability of inner classes to automatically reference the fields of the outer class does not exist in Apex as it does in Java. If you need to reference the outer class fields you will have to include your own constructor that takes a reference to the outer class.)

Inner classes can reference private static methods in the outer class; this is useful to share utility code used by more than one inner class that doesn't merit being public.

6
  • Can you think of any other instances where it has to be top-level? I guess batch implementations?
    – Adrian Larson
    Commented Aug 25, 2016 at 21:56
  • 4
    @AdrianLarson Yeah I think you are right about batchable. Another awkward area (at least for managed package authors) is Type.forName logic where you are trying to support namespaced and non-namespaced classes: does 1 dot in the name mean outer.inner or namespace.outer?
    – Keith C
    Commented Aug 25, 2016 at 22:00
  • Yeah, that makes sense that dynamic Type instantiation would be complicated by it. Thanks.
    – Adrian Larson
    Commented Aug 25, 2016 at 22:01
  • Inner classes can reference private static methods in the outer class - this is new to me. private I guess just means not visible outside of the top level class. Can the outer class use private static methods of the inner class? Commented Feb 29, 2020 at 20:13
  • 2
    Hi @BrianMiller, Inner classes can't have static methods so no. But I've found the other way round useful when the utility static methods are tightly related to the inner classes and not of value elsewhere.
    – Keith C
    Commented Feb 29, 2020 at 20:24

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .