Note: This release is in preview. Features described here don’t become generally available until the latest general availability date that Salesforce announces for this release. Before then, and where features are noted as beta, pilot, or developer preview, we can’t guarantee general availability within any particular time frame or at all. Make your purchase decisions only on the basis of generally available products and features.

Extended Class Example

The following is an extended example of a class, showing all the features of Apex classes. The keywords and concepts introduced in the example are explained in more detail throughout this chapter.

1// Top-level (outer) class must be public or global (usually public unless they contain
2// a Web Service, then they must be global)
3public class OuterClass {
4
5  // Static final variable (constant) – outer class level only
6  private static final Integer MY_INT;
7
8  // Non-final static variable - use this to communicate state across triggers
9  // within a single request)
10  public static String sharedState;
11  
12  // Static method - outer class level only
13  public static Integer getInt() { return MY_INT; }
14
15  // Static initialization (can be included where the variable is defined)
16  static {
17    MY_INT = 2; 
18  }
19
20  // Member variable for outer class
21  private final String m;
22
23  // Instance initialization block - can be done where the variable is declared, 
24  // or in a constructor
25  {
26    m = 'a';  
27  }
28  
29  // Because no constructor is explicitly defined in this outer class, an implicit, 
30  // no-argument, public constructor exists
31
32  // Inner interface
33  public virtual interface MyInterface { 
34
35    // No access modifier is necessary for interface methods - these are always 
36    // public or global depending on the interface visibility
37    void myMethod(); 
38  }
39
40  // Interface extension
41  interface MySecondInterface extends MyInterface { 
42    Integer method2(Integer i); 
43  }
44
45  // Inner class - because it is virtual it can be extended.
46  // This class implements an interface that, in turn, extends another interface.
47  // Consequently the class must implement all methods.
48  public virtual class InnerClass implements MySecondInterface {
49
50    // Inner member variables
51    private final String s;
52    private final String s2;
53
54    // Inner instance initialization block (this code could be located above)
55    {
56       this.s = 'x';
57    }
58
59    // Inline initialization (happens after the block above executes)
60    private final Integer i = s.length();
61 
62    // Explicit no argument constructor
63    InnerClass() {
64       // This invokes another constructor that is defined later
65       this('none');
66    }
67
68    // Constructor that assigns a final variable value
69    public InnerClass(String s2) { 
70      this.s2 = s2; 
71    }
72
73    // Instance method that implements a method from MyInterface.
74    // Because it is declared virtual it can be overridden by a subclass.
75    public virtual void myMethod() { /* does nothing */ }
76
77    // Implementation of the second interface method above.
78    // This method references member variables (with and without the "this" prefix)
79    public Integer method2(Integer i) { return this.i + s.length(); }
80  }
81
82  // Abstract class (that subclasses the class above). No constructor is needed since
83  // parent class has a no-argument constructor
84  public abstract class AbstractChildClass extends InnerClass {
85
86    // Override the parent class method with this signature.
87    // Must use the override keyword
88    public override void myMethod() { /* do something else */ }
89
90    // Same name as parent class method, but different signature.
91    // This is a different method (displaying polymorphism) so it does not need
92    // to use the override keyword
93    protected void method2() {}
94
95    // Abstract method - subclasses of this class must implement this method
96    public abstract Integer abstractMethod();
97  }
98
99  // Complete the abstract class by implementing its abstract method
100  public class ConcreteChildClass extends AbstractChildClass {
101    // Here we expand the visibility of the parent method - note that visibility 
102    // cannot be restricted by a sub-class
103    public override Integer abstractMethod() { return 5; }
104  }
105
106  // A second sub-class of the original InnerClass
107  public class AnotherChildClass extends InnerClass {
108    AnotherChildClass(String s) {
109      // Explicitly invoke a different super constructor than one with no arguments
110      super(s);
111    }
112  }
113  
114  // Exception inner class
115  public virtual class MyException extends Exception {
116    // Exception class member variable
117    public Double d;
118
119    // Exception class constructor    
120    MyException(Double d) {
121      this.d = d;
122    }
123    
124    // Exception class method, marked as protected
125    protected void doIt() {}
126  }
127  
128  // Exception classes can be abstract and implement interfaces
129  public abstract class MySecondException extends Exception implements MyInterface {
130  }
131}
This code example illustrates:
  • A top-level class definition (also called an outer class)
  • Static variables and static methods in the top-level class, as well as static initialization code blocks
  • Member variables and methods for the top-level class
  • Classes with no user-defined constructor — these have an implicit, no-argument constructor
  • An interface definition in the top-level class
  • An interface that extends another interface
  • Inner class definitions (one level deep) within a top-level class
  • A class that implements an interface (and, therefore, its associated sub-interface) by implementing public versions of the method signatures
  • An inner class constructor definition and invocation
  • An inner class member variable and a reference to it using the this keyword (with no arguments)
  • An inner class constructor that uses the this keyword (with arguments) to invoke a different constructor
  • Initialization code outside of constructors — both where variables are defined, as well as with anonymous blocks in curly braces ({}). Note that these execute with every construction in the order they appear in the file, as with Java.
  • Class extension and an abstract class
  • Methods that override base class methods (which must be declared virtual)
  • The override keyword for methods that override subclass methods
  • Abstract methods and their implementation by concrete sub-classes
  • The protected access modifier
  • Exceptions as first class objects with members, methods, and constructors

This example shows how the class above can be called by other Apex code:

1// Construct an instance of an inner concrete class, with a user-defined constructor
2OuterClass.InnerClass ic = new OuterClass.InnerClass('x');
3
4// Call user-defined methods in the class
5System.assertEquals(2, ic.method2(1));
6
7// Define a variable with an interface data type, and assign it a value that is of 
8// a type that implements that interface
9OuterClass.MyInterface mi = ic;
10
11// Use instanceof and casting as usual
12OuterClass.InnerClass ic2 = mi instanceof OuterClass.InnerClass ? 
13                            (OuterClass.InnerClass)mi : null;
14System.assert(ic2 != null);
15
16// Construct the outer type
17OuterClass o = new OuterClass();
18System.assertEquals(2, OuterClass.getInt());
19
20// Construct instances of abstract class children
21System.assertEquals(5, new OuterClass.ConcreteChildClass().abstractMethod());
22
23// Illegal - cannot construct an abstract class
24// new OuterClass.AbstractChildClass();
25
26// Illegal – cannot access a static method through an instance
27// o.getInt();
28
29// Illegal - cannot call protected method externally
30// new OuterClass.ConcreteChildClass().method2();
This code example illustrates:
  • Construction of the outer class
  • Construction of an inner class and the declaration of an inner interface type
  • A variable declared as an interface type can be assigned an instance of a class that implements that interface
  • Casting an interface variable to be a class type that implements that interface (after verifying this using the instanceof operator)