与 Java 一样,您可以在 Apex Class中创建类。类是用于创建对象的模板或蓝图。对象是类的实例。
例如,该类描述整个购买 订单,以及您可以使用采购订单执行的所有操作。类的实例是特定的采购订单 您发送或接收的内容。PurchaseOrderPurchaseOrder
所有对象都有状态和行为,即 对象知道自己,以及对象可以做的事情。状态 PurchaseOrder 对象(它所知道的对象)包括发送它的用户、日期 以及它的创建时间,以及它是否被标记为重要。行为 PurchaseOrder 对象(它可以做什么)包括检查库存、发货 产品,或通知客户。
类可以包含变量和方法。变量用于指定 对象,例如对象的 或 .由于这些变量与 类并且是它的成员,它们通常被称为成员 变量。方法用于控制行为,例如 或 。NameTypegetOtherQuotescopyLineItems
类可以包含其他类、异常类型和初始化代码。
接口就像一个类,其中没有一个 方法已实现 – 方法签名在那里,但 每个方法都是空的。要使用接口,另一个类必须通过提供 接口中包含的所有方法的主体。
有关类、对象和接口的更多常规信息,请参阅 http://java.sun.com/docs/books/tutorial/java/concepts/index.html
除了类之外,Apex 还提供触发器、 类似于数据库触发器。触发器是执行的 Apex 代码 在数据库操作之前或之后。请参阅触发器。
- Apex 类定义
- 类变量
- 类方法
- 使用构造函数
- 访问修饰符
- 静态和实例方法、变量和初始化代码
在 Apex 中,您可以拥有静态方法、变量和初始化代码。但是,Apex 类不能是静态的。还可以具有实例方法、成员变量和初始化代码(没有修饰符)和局部变量。
- Apex 属性
- 扩展类
可以扩展类以提供更专业的行为。
- 扩展类示例
Apex 类定义
在 Apex 中,您可以定义顶级类(也称为外部类)以及内部类, 也就是说,在另一个类中定义的类。内部类只能有一个级别深。为 例:
public class myOuterClass {
// Additional myOuterClass code here
class myInnerClass {
// myInnerClass code here
}
}
若要定义类,请指定以下内容:
- 访问修饰符:
- 您必须在顶级的声明中使用访问修饰符之一(如 或 ) 类。publicglobal
- 不必在内部类的声明中使用访问修饰符。
- 可选的定义修饰符(如 、 等)virtualabstract
- 必需:关键字后跟类名称class
- 可选扩展或实现,或两者兼而有之
注意
避免对类名使用标准对象名。这样做 导致意外结果。有关标准对象的列表,请参阅 Salesforce 的对象参考。
使用以下语法定义类:
private | public | global
[virtual | abstract | with sharing | without sharing]
class ClassName [implements InterfaceNameList] [extends ClassName]
{
// The body of the class
}
- access 修饰符声明此类是 仅在本地知道,即仅通过这部分代码知道。这是默认设置 内部类的访问权限 – 也就是说,如果未指定访问修饰符 对于内部类,它被认为是 .此关键字只能与内部类(或 标有注解的顶级测试类)。privateprivate@IsTest
- 访问修饰符 声明此类在应用程序或命名空间中可见。public
- access 修饰符声明此类是 所有 Apex 代码都广为人知。global所有班级 包含用关键字定义的方法必须声明为 。如果方法或内部类是 声明为 ,外部, 顶级类也必须定义为 。webserviceglobalglobalglobal
- 和关键字指定此类的共享模式。欲了解更多信息, 请参阅使用有共享、无共享和继承共享关键字。with sharingwithout sharing
- 定义修饰符声明此 类允许扩展和覆盖。不能使用关键字重写方法,除非类 已定义为 。virtualoverridevirtual
- 定义 modifier 声明此类包含抽象方法, 是,只声明其签名而不定义主体的方法。abstract
注意
- 在将抽象方法上传到全局类后,无法将抽象方法添加到全局类中 托管 – 已发布的包版本。
- 如果“托管 – 已发布”包中的类是虚拟的,则可以向其添加的方法 还必须是虚拟的,并且必须具有实现。
- 不能重写已安装的全局类的公共或受保护的虚拟方法 托管包。
有关托管包的详细信息,请参阅什么是包?。
一个类可以实现多个接口,但只能扩展一个现有类。此限制 表示 Apex 不支持多重继承。列表中的接口名称 用逗号分隔。有关接口的详细信息,请参阅接口。
有关方法和变量访问修饰符的更多信息,请参见访问修饰符。
类变量
若要声明变量,请指定以下内容:
- 可选:修饰符,例如 或 ,以及 。publicfinalstatic
- 必需:变量的数据类型,例如 String 或 Boolean。
- 必需:变量的名称。
- 可选:变量的值。
定义 变量:
[public | private | protected | global] [final] [static] data_type variable_name
[= value]
例如:
private static final Integer MY_INT;
private final Integer i = 1;
版本化行为更改
在 API 版本 50.0 及更高版本中,范围和可访问性规则强制执行 带注释的 Apex 变量、方法、内部类和接口 跟。为 辅助功能注意事项,请参阅 NamespaceAccessible 注释。有关基于命名空间的可见性的详细信息, 请参阅基于命名空间 第二代软件包中 Apex 类的可见性。@namespaceAccessible
类方法
若要定义方法,请指定以下内容:
- 可选:修饰符,例如 或 .publicprotected
- 必需:方法返回的值的数据类型,例如 String 或 整数。如果方法不使用,请使用 返回一个值。void
- 必需:方法的输入参数列表,用逗号分隔,每个参数 前面是其数据类型,并括在括号中。如果没有参数,请使用 空括号。一个方法只能有 32 个输入参数。()
- 必需:方法的主体,用大括号括起来。该方法的所有代码,包括 此处包含任何局部变量声明。{}
定义 方法:
[public | private | protected | global] [override] [static] data_type method_name
(input parameters)
{
// The body of the method
}
注意
您可以使用 仅在已定义为 或 的类中覆盖方法。overridevirtualabstract例如:
public static Integer getInt() {
return MY_INT;
}
与 Java 一样,返回值的方法也可以作为语句运行,如果其结果 未分配给其他变量。用户定义的方法:
- 可以在使用系统方法的任何地方使用。
- 可以是递归的。
- 可能会产生副作用,例如初始化 sObject 记录 ID 的 DML 语句。请参阅 Apex DML 语句。insert
- 可以引用它们自己或稍后在同一类中定义的方法,或者 匿名块。Apex 分两个阶段解析方法,因此 forward 声明 不需要。
- 可以是多态性的。例如,可以通过两种方式实现名为的方法,一种是使用单个 Integer 参数,一个包含两个 Integer 参数。取决于方法是否 调用一个或两个整数,Apex 解析器选择适当的 要执行的实现。如果解析器找不到完全匹配,则 使用类型强制规则寻求近似匹配。欲了解更多信息 数据转换,详见 转换。example注意如果解析器找到多个近似匹配项,则 生成解析时异常。
- 具有 void 返回类型的方法通常作为独立语句调用 在 Apex 代码中。为 例:
System.debug('Here is a note for the log.');
- 可以有返回值作为语句运行的语句,如果它们的 结果不会分配给其他变量。此规则在 Java 中相同。
按值传递方法参数
在 Apex 中,所有原始数据类型参数,例如 Integer 或 String,按值传递到方法中。这一事实意味着对 参数仅存在于方法的范围内。当方法 返回时,对参数的更改将丢失。
非基元数据类型参数(如 sObjects)是 通过引用传递到方法中。因此,当该方法返回时, 传入的参数仍引用与方法调用之前相同的对象。 在该方法中,不能更改引用以指向另一个对象,但 可以更改对象字段的值。
以下是传递基元和非基元数据类型参数的示例 into 方法。
示例:传递基元数据类型参数此示例演示如何将 String 类型的基元参数按值传递到 另一种方法。此示例中的方法创建一个 String 变量 , 和 为其赋值。然后,它将此变量作为参数传递给另一个方法, 修改此 String 的值。但是,由于 String 是基元类型, 它是按值传递的,当方法返回时,原始的值 变量 , 保持不变。assert 语句验证 的价值仍然是旧的 价值。
debugStatusMessagemsgmsgmsg
public class PassPrimitiveTypeExample {
public static void debugStatusMessage() {
String msg = 'Original value';
processString(msg);
// The value of the msg variable didn't
// change; it is still the old value.
System.assertEquals(msg, 'Original value');
}
public static void processString(String s) {
s = 'Modified value';
}
}
示例:传递非基元数据类型参数
此示例演示如何通过引用将 List 参数传递到方法中并对其进行修改。然后 在方法中,显示 不能将 List 参数更改为指向另一个 List 对象。reference()referenceNew()一、方法 创建一个变量 ,该变量是整数列表并传递 它变成了一种方法。调用的方法使用表示的整数值填充此列表 四舍五入的温度值。当该方法返回时,assert 语句将验证 原始 List 变量的内容已更改,现在包含五个 值。接下来,该示例创建第二个 List 变量 ,并将其传递给另一个方法。调用的方法 将传入的参数分配给新创建的包含新 Integer 的 List 值。当方法返回时,原始变量 不指向新列表,但仍指向原始列表,该列表为空。 assert 语句验证不包含 值。
createTemperatureHistoryfillMecreateMecreateMecreateMe
public class PassNonPrimitiveTypeExample {
public static void createTemperatureHistory() {
List<Integer> fillMe = new List<Integer>();
reference(fillMe);
// The list is modified and contains five items
// as expected.
System.assertEquals(fillMe.size(),5);
List<Integer> createMe = new List<Integer>();
referenceNew(createMe);
// The list is not modified because it still points
// to the original list, not the new list
// that the method created.
System.assertEquals(createMe.size(),0);
}
public static void reference(List<Integer> m) {
// Add rounded temperatures for the last five days.
m.add(70);
m.add(68);
m.add(75);
m.add(80);
m.add(82);
}
public static void referenceNew(List<Integer> m) {
// Assign argument to a new List of
// five temperature values.
m = new List<Integer>{55, 59, 62, 60, 63};
}
}
版本化行为更改
在 API 版本 50.0 及更高版本中,范围和可访问性规则在 Apex 上强制执行 用 注释的变量、方法、内部类和接口。对于可访问性 注意事项,请参阅 NamespaceAccessible 注释。有关基于命名空间的可见性的详细信息,请参阅基于命名空间的可见性 适用于第二代软件包中的 Apex 类。@namespaceAccessible
使用构造函数
构造函数是从类创建对象时调用的代码 蓝图。您不需要为每个类编写构造函数。如果一个类没有 用户定义的构造函数,使用默认的、无参数的公共构造函数。
构造函数的语法类似于方法,但有所不同 从方法定义,因为它从来就没有显式返回类型 并且它不会被从它创建的对象继承。编写类的构造函数后,必须使用关键字才能实例化 该类中的对象,使用该构造函数。例如,使用 以下类:
new
public class TestObject {
// The no argument constructor
public TestObject() {
// more code here
}
}
可以使用以下命令实例化此类型的新对象 法典:
TestObject myTest = new TestObject();
如果编写一个接受参数的构造函数,则可以使用该构造函数创建一个 对象。
如果创建接受参数的构造函数,并且仍希望使用无参数 构造函数,则必须在代码中创建自己的无参数构造函数。创建 构造函数,则您不再有权访问默认的无参数公共 构造 函数。在 Apex 中,构造函数可以重载,也就是说,可以 一个类的多个构造函数,每个构造函数都有不同的参数。 下面的示例演示一个具有两个构造函数的类:一个 没有参数,并且采用简单的 Integer 参数。它 还阐释了一个构造函数如何使用 语法,也 称为构造函数链接。
this(…)
public class TestObject2 {
private static final Integer DEFAULT_SIZE = 10;
Integer size;
//Constructor with no arguments
public TestObject2() {
this(DEFAULT_SIZE); // Using this(...) calls the one argument constructor
}
// Constructor with one argument
public TestObject2(Integer ObjectSize) {
size = ObjectSize;
}
}
可以使用以下命令实例化此类型的新对象 法典:
TestObject2 myObject1 = new TestObject2(42);
TestObject2 myObject2 = new TestObject2();
为类创建的每个构造函数都必须具有不同 参数列表。在下面的示例中,所有构造函数都是 可能:
public class Leads {
// First a no-argument constructor
public Leads () {}
// A constructor with one argument
public Leads (Boolean call) {}
// A constructor with two arguments
public Leads (String email, Boolean call) {}
// Though this constructor has the same arguments as the
// one above, they are in a different order, so this is legal
public Leads (Boolean call, String email) {}
}
定义新类时,就是在定义新的数据类型。 您可以在任何可以使用其他数据类型名称的地方使用类名, 例如 String、Boolean 或 Account。如果定义一个变量,其 type 是一个类,分配给它的任何对象都必须是 该类或子类。
访问修饰符
Apex 允许您使用 、 、 和 access 修饰符 定义方法和变量时。privateprotectedpublicglobal
虽然触发器和匿名块也可以使用这些访问修饰符,但它们在 Apex 的较小部分。例如,将方法声明为匿名块中的方法并不能调用 它来自该代码的外部。global
有关类访问修饰符的更多信息,请参见 Apex 类定义。
注意
接口方法没有访问修饰符。它们始终是全球性的。有关详细信息,请参阅接口。
默认情况下,方法或变量仅对定义中的 Apex 代码可见 类。显式指定方法或变量为公共方法或变量,以便将其指定为 public 可用于同一应用程序命名空间中的其他类(请参阅命名空间前缀)。您可以更改 使用以下访问修饰符的可见性级别:private此访问修饰符是默认值,表示 方法或变量只能在定义它的 Apex 类中访问。 如果未指定访问修饰符,则方法或变量为 .privateprotected这意味着该方法或变量对 定义 Apex 类,以及扩展定义 Apex 类的类。您可以 仅将此访问修饰符用于实例方法和成员变量。此设置 严格来说,它比默认(私有)设置更宽松,就像 Java 一样。public这表示方法或变量可供所有人访问 特定包中的 Apex。适用于所有第二代 (2GP) 共享命名空间的托管包与注释一起使用。在 no-namespace 包将 Apex 代码隐式呈现为 @NamespaceAccessible。public@NamespaceAccessible
注意
在 Apex 中,访问 modifier 与 Java 中的修饰符不同。这样做是为了阻止加入 应用程序,以将每个应用程序的代码分开。在 Apex 中,如果您愿意 要像在 Java 中那样公开某些内容,必须使用 access 修饰符。publicglobal有关基于命名空间的可见性的详细信息,请参阅基于命名空间的可见性 适用于第二代软件包中的 Apex 类。global这表示该方法或变量可以由任何 Apex 代码使用 可以访问该类,而不仅仅是同一应用程序中的 Apex 代码。这 访问修饰符必须用于必须在 应用程序,无论是在 SOAP API 中还是通过其他 Apex 代码。如果声明方法或 变量为 ,您还必须声明 以 .globalglobal
注意
我们建议很少使用访问修饰符(如果有的话)。跨应用程序 依赖关系难以维护。global
要使用 、 、 或 access 修饰符,请使用 语法如下:privateprotectedpublicglobal
[(none)|private|protected|public|global] declaration
例如:
// private variable s1
private string s1 = '1';
// public method getsz()
public string getsz() {
...
}
静态和实例方法、变量和初始化 法典
在 Apex 中,您可以拥有静态方法、变量和初始化 法典。但是,Apex 类不能是静态的。还可以具有实例方法、成员变量和初始化代码(没有修饰符)和局部变量。
特性
静态方法、变量和初始化代码具有这些特征。
- 它们与类相关联。
- 它们只允许在外部类中使用。
- 它们仅在加载类时初始化。
- 它们不会作为 Visualforce 页面视图状态的一部分进行传输。
实例方法、成员变量和初始化代码具有这些 特性。
- 它们与特定对象相关联。
- 它们没有定义修饰符。
- 它们是使用从它们所在的类实例化的每个对象创建的 宣布。
局部变量具有这些特征。
- 它们与声明它们的代码块相关联。
- 在使用它们之前,必须对其进行初始化。
下面的示例演示一个局部变量,其作用域是代码块的持续时间。if
Boolean myCondition = true;
if (myCondition) {
integer localVariable = 10;
}
使用静态方法和变量
只能将静态方法和变量用于外部类。内部类有 没有静态方法或变量。静态方法或变量不需要 类的实例。
在创建类的对象之前,类中的所有静态成员变量都是 初始化,并执行所有静态初始化代码块。这些项目是 按照它们在类中出现的顺序进行处理。
静态方法用作实用程序方法,它从不依赖于 实例成员变量。因为静态方法只与类相关联, 它无法访问其类的实例成员变量值。
静态变量仅在 Apex 事务范围内是静态的。 它不是整个服务器或整个组织的静态。a 的值 静态变量在单个事务的上下文中保留并重置 跨越事务边界。例如,如果 Apex DML 请求导致触发器 若要多次触发,静态变量会在这些触发器中保留 调用。
若要存储跨类实例共享的信息,请使用静态 变量。同一类的所有实例共享静态的单个副本 变量。例如,单个事务生成的所有触发器都可以通信 通过查看和更新相关类中的静态变量来相互关联。一个 递归触发器可以使用类变量的值来确定何时退出 递归。
假设您有以下类。
public class P {
public static boolean firstRun = true;
}
然后,使用此类的触发器可能会选择性地使 触发。
trigger T1 on Account (before delete, after delete, after undelete) {
if(Trigger.isBefore){
if(Trigger.isDelete){
if(p.firstRun){
Trigger.old[0].addError('Before Account Delete Error');
p.firstRun=false;
}
}
}
}
触发器中定义的静态变量不会在不同 同一事务中的触发上下文,例如在插入之前和 插入调用后。相反,在类中定义静态变量,以便 触发器可以访问这些类成员变量并检查其静态变量 值。
无法通过类的实例访问类静态变量。如果类有一个静态变量,并且是 的实例,则不是合法的表达式。MyClassmyStaticVariablemyClassInstanceMyClassmyClassInstance.myStaticVariable
实例方法也是如此。如果是静态方法,则不合法。相反,请参考那些 使用类的静态标识符: 和 .myStaticMethod()myClassInstance.myStaticMethod()MyClass.myStaticVariableMyClass.myStaticMethod()局部变量名在类名之前计算。如果局部变量具有 与类同名,局部变量隐藏了 同名。例如,如果注释掉该行,则此方法有效。但是,如果包含该行,则该方法不会 compile,因为 Salesforce 报告该方法不存在或具有 不對 签名。
StringString
public static void method() {
String Database = '';
Database.insert(new Account());
}
内部类的行为类似于静态 Java 内部类, 但不需要关键字。 内部类可以像外部类一样具有实例成员变量,但 没有指向外部类实例的隐式指针(使用 关键字)。staticthis
注意
在 API 版本 20.0 及更早版本中,如果批量 API 请求导致触发器触发, 触发器要处理的 200 条记录的每个块被拆分为 100 条记录的块 记录。在 Salesforce API 版本 21.0 及更高版本中,不再拆分 API 区块 发生。如果批量 API 请求导致触发器多次触发 200 条记录,调控器限制在这些触发器调用之间重置 相同的 HTTP 请求。
使用实例方法和变量
实例方法和成员变量由类的实例使用,即 一个对象。实例成员变量在类中声明,但不在类中声明 方法。实例方法通常使用实例成员变量来影响 方法的行为。
假设您希望有一个收集二维点和绘图的类 它们在图表上。下面的框架类使用成员变量来保存列表 的点和一个内部类来管理二维点列表。
public class Plotter {
// This inner class manages the points
class Point {
Double x;
Double y;
Point(Double x, Double y) {
this.x = x;
this.y = y;
}
Double getXCoordinate() {
return x;
}
Double getYCoordinate() {
return y;
}
}
List<Point> points = new List<Point>();
public void plot(Double x, Double y) {
points.add(new Point(x, y));
}
// The following method takes the list of points and does something with them
public void render() {
}
}
使用初始化代码
实例初始化代码是定义以下形式的代码块 在课堂上。
{
//code body
}
每次对象执行时,都会执行类中的实例初始化代码 从该类实例化。这些代码块在构造函数之前运行。
如果不想为类编写自己的构造函数,可以使用实例 初始化代码块,用于初始化实例变量。在简单的情况下, 使用普通的初始值设定项。为复杂情况保留初始化代码, 例如初始化静态映射。静态初始化块只运行一次, 不管您访问包含它的类多少次。
静态初始化代码是以关键字 开头的代码块。static
static {
//code body
}
与其他静态代码类似,静态初始化代码块仅初始化 第一次使用类时一次。
一个类可以具有任意数量的静态或实例初始化代码块。 它们可以出现在代码正文中的任何位置。代码块按以下顺序执行 它们出现在文件中,就像它们在 Java 中一样。
您可以使用静态初始化代码来初始化静态最终变量,并 声明静态信息,例如值映射。例如:
public class MyClass {
class RGB {
Integer red;
Integer green;
Integer blue;
RGB(Integer red, Integer green, Integer blue) {
this.red = red;
this.green = green;
this.blue = blue;
}
}
static Map<String, RGB> colorMap = new Map<String, RGB>();
static {
colorMap.put('red', new RGB(255, 0, 0));
colorMap.put('cyan', new RGB(0, 255, 255));
colorMap.put('magenta', new RGB(255, 0, 255));
}
}
版本化行为更改
在 API 版本 50.0 及更高版本中,范围和可访问性规则在 Apex 上强制执行 用 注释的变量、方法、内部类和接口。对于可访问性 注意事项,请参阅 NamespaceAccessible 注释。有关基于命名空间的可见性的详细信息,请参阅基于命名空间的可见性 适用于第二代软件包中的 Apex 类。@namespaceAccessible
Apex 属性
Apex 属性类似于变量; 但是,您可以在代码中对属性值执行其他操作,然后再将其 访问或返回。属性可用于在更改之前验证数据 made,用于在数据发生更改时提示操作(例如更改其他值 成员变量),或公开从其他源检索到的数据(例如 作为另一个类)。属性定义包括一个或两个代码块,表示 get 访问器和 SET 访问器:
- get 访问器中的代码在读取属性时执行。
- 当为属性分配新值时,将执行 set 访问器中的代码。
如果属性只有 get 访问器,则将其视为只读。如果属性只有 set 访问器,则将其视为只写。考虑具有两个访问器的属性 读写。
若要声明属性,请在类的主体中使用以下语法:
Public class BasicClass {
// Property declaration
access_modifier return_type property_name {
get {
//Get accessor code block
}
set {
//Set accessor code block
}
}
}
哪里:
- access_modifier是属性的访问修饰符。这 可应用于属性的访问修饰符包括:、、 和 。此外,这些定义 可以应用修饰符:和 。有关访问的更多信息 修饰符,请参阅 Access 修饰符。publicprivateglobalprotectedstatictransient
- return_type是属性的类型,例如 Integer、Double、 sObject 等。有关详细信息,请参阅数据类型。
- property_name是属性的名称
例如,下面的类定义了一个名为 的属性。该物业是公共的。该属性返回整数数据类型。prop
public class BasicProperty {
public integer prop {
get { return prop; }
set { prop = value; }
}
}
下面的代码段调用 BasicProperty 类,执行 get 和 set 访问:
BasicProperty bp = new BasicProperty();
bp.prop = 5; // Calls set accessor
System.assertEquals(5, bp.prop); // Calls get accessor
请注意以下事项:
- get 访问器的主体类似于方法的主体。它必须返回值 属性类型。执行 get 访问器与读取 变量。
- get 访问器必须以 return 语句结尾。
- 建议 get 访问器不要更改其对象的状态 定义上。
- set 访问器类似于返回类型为 void 的方法。
- 为属性赋值时,将使用参数调用 set 访问器 这提供了新的价值。
- 在 API 版本 42.0 及更高版本中,除非在 set 访问器中设置了变量值,否则 无法在 GET 访问器中更新其值。
- 调用 set 访问器时,系统会将隐式参数传递给 setter 调用的数据类型与 财产。value
- 不能在接口上定义属性。
- Apex 属性基于 C# 中的对应属性,但存在以下差异:
- 属性直接为值提供存储。您无需创建 支持用于存储值的成员。
- 可以在 Apex 中创建自动属性。有关详细信息,请参阅使用自动属性。
使用自动属性
属性不需要在其 get 或 set 访问器代码块中使用其他代码。 相反,您可以将 get 和 set 访问器代码块留空以定义自动属性。自动属性允许您编写更多内容 紧凑的代码,更易于调试和维护。它们可以声明为 只读、读写或只写。以下示例创建三个自动 性能:
public class AutomaticProperty {
public integer MyReadOnlyProp { get; }
public double MyReadWriteProp { get; set; }
public string MyWriteOnlyProp { set; }
}
以下代码段练习这些属性:
AutomaticProperty ap = new AutomaticProperty();
ap.MyReadOnlyProp = 5; // This produces a compile error: not writable
ap.MyReadWriteProp = 5; // No error
System.assertEquals(5, ap.MyWriteOnlyProp); // This produces a compile error: not readable
使用静态属性
当属性声明为 时, 属性的访问器方法在静态上下文中执行。因此,访问器不会 有权访问类中定义的非静态成员变量。以下 示例创建一个同时具有静态属性和实例属性的类:static
public class StaticProperty {
private static integer StaticMember;
private integer NonStaticMember;
// The following produces a system error
// public static integer MyBadStaticProp { return NonStaticMember; }
public static integer MyGoodStaticProp {
get {return StaticMember;}
set { StaticMember = value; }
}
public integer MyGoodNonStaticProp {
get {return NonStaticMember;}
set { NonStaticMember = value; }
}
}
以下代码段调用静态属性和实例属性:
StaticProperty sp = new StaticProperty();
// The following produces a system error: a static variable cannot be
// accessed through an object instance
// sp.MyGoodStaticProp = 5;
// The following does not produce an error
StaticProperty.MyGoodStaticProp = 5;
在属性上使用访问修饰符 访问
可以使用自己的访问修饰符定义属性访问器。如果访问器 包含它自己的访问修饰符,这个修饰符覆盖了 财产。单个访问器的访问修饰符必须更具限制性 而不是属性本身的访问修饰符。例如,如果属性具有 被定义为 ,个人 访问器不能定义为 。这 以下类定义显示了其他示例:publicglobal
global virtual class PropertyVisibility {
// X is private for read and public for write
public integer X { private get; set; }
// Y can be globally read but only written within a class
global integer Y { get; public set; }
// Z can be read within the class but only subclasses can set it
public integer Z { get; protected set; }
}
扩展类
您可以扩展类以提供更专业的行为。
扩展另一个类的类继承了 扩展类。此外,扩展类可以覆盖现有的虚拟类 方法,方法是在方法定义中使用 override 关键字。覆盖虚拟 方法允许您为现有方法提供不同的实现。这 表示特定方法的行为因对象而异 你正在召唤它。这称为多态性。
一个类使用类定义中的关键字扩展另一个类。一个类只能扩展另一个类,但它可以 实现多个接口。extends
此示例演示类如何 扩展类。运行继承 示例 在本节中,首先创建类。YellowMarkerMarkerMarker
public virtual class Marker {
public virtual void write() {
System.debug('Writing some text.');
}
public virtual Double discount() {
return .05;
}
}
然后创建类,该类扩展 类。YellowMarkerMarker
// Extension for the Marker class
public class YellowMarker extends Marker {
public override void write() {
System.debug('Writing some text using the yellow marker.');
}
}
此代码段显示多态性。该示例声明两个相同类型的对象 ().即使两个对象都是 标记,则将第二个对象分配给类的实例。因此,在其上调用该方法会产生与 在第一个对象上调用此方法,因为此方法已被重写。 但是,您可以在 第二个对象,即使此方法不是类定义的一部分。但它是扩展类的一部分,并且 因此,可用于扩展类 .在 Execute Anonymous 窗口中运行此代码段 开发 人员 安慰。
MarkerYellowMarkerwritediscountYellowMarkerYellowMarker
Marker obj1, obj2;
obj1 = new Marker();
// This outputs 'Writing some text.'
obj1.write();
obj2 = new YellowMarker();
// This outputs 'Writing some text using the yellow marker.'
obj2.write();
// We get the discount method for free
// and can call it from the YellowMarker instance.
Double d = obj2.discount();
扩展类可以具有更多与原始类不常见的方法定义 扩展类。在此示例中,该类扩展了该类,并具有一个额外的类 方法,不适用于 类。要调用额外的方法,请 对象类型必须是扩展类。RedMarkerMarkercomputePriceMarker
在运行下一个代码段之前,请创建该类,这需要组织中的类。RedMarkerMarker
// Extension for the Marker class
public class RedMarker extends Marker {
public override void write() {
System.debug('Writing some text in red.');
}
// Method only in this class
public Double computePrice() {
return 1.5;
}
}
此代码片段演示如何对类调用其他方法。在“执行”中运行此代码片段 开发者控制台的匿名窗口。RedMarker
RedMarker obj = new RedMarker();
// Call method specific to RedMarker only
Double price = obj.computePrice();
扩展也适用于接口 – 一个接口可以扩展另一个接口。如 使用类,当一个接口扩展另一个接口时,所有方法和 扩展接口的属性可用于扩展接口。
版本化行为更改
在 API 版本 50.0 及更高版本中,范围和可访问性规则在 Apex 上强制执行 用 注释的变量、方法、内部类和接口。对于可访问性 注意事项,请参阅 NamespaceAccessible 注释。有关基于命名空间的可见性的详细信息,请参阅基于命名空间的可见性 适用于第二代软件包中的 Apex 类。@namespaceAccessible
扩展类示例
下面是一个类的扩展示例,显示了所有 Apex 类的功能。示例中介绍的关键字和概念是 在本章中进行了更详细的解释。
// Top-level (outer) class must be public or global (usually public unless they contain
// a Web Service, then they must be global)
public class OuterClass {
// Static final variable (constant) – outer class level only
private static final Integer MY_INT;
// Non-final static variable - use this to communicate state across triggers
// within a single request)
public static String sharedState;
// Static method - outer class level only
public static Integer getInt() { return MY_INT; }
// Static initialization (can be included where the variable is defined)
static {
MY_INT = 2;
}
// Member variable for outer class
private final String m;
// Instance initialization block - can be done where the variable is declared,
// or in a constructor
{
m = 'a';
}
// Because no constructor is explicitly defined in this outer class, an implicit,
// no-argument, public constructor exists
// Inner interface
public virtual interface MyInterface {
// No access modifier is necessary for interface methods - these are always
// public or global depending on the interface visibility
void myMethod();
}
// Interface extension
interface MySecondInterface extends MyInterface {
Integer method2(Integer i);
}
// Inner class - because it is virtual it can be extended.
// This class implements an interface that, in turn, extends another interface.
// Consequently the class must implement all methods.
public virtual class InnerClass implements MySecondInterface {
// Inner member variables
private final String s;
private final String s2;
// Inner instance initialization block (this code could be located above)
{
this.s = 'x';
}
// Inline initialization (happens after the block above executes)
private final Integer i = s.length();
// Explicit no argument constructor
InnerClass() {
// This invokes another constructor that is defined later
this('none');
}
// Constructor that assigns a final variable value
public InnerClass(String s2) {
this.s2 = s2;
}
// Instance method that implements a method from MyInterface.
// Because it is declared virtual it can be overridden by a subclass.
public virtual void myMethod() { /* does nothing */ }
// Implementation of the second interface method above.
// This method references member variables (with and without the "this" prefix)
public Integer method2(Integer i) { return this.i + s.length(); }
}
// Abstract class (that subclasses the class above). No constructor is needed since
// parent class has a no-argument constructor
public abstract class AbstractChildClass extends InnerClass {
// Override the parent class method with this signature.
// Must use the override keyword
public override void myMethod() { /* do something else */ }
// Same name as parent class method, but different signature.
// This is a different method (displaying polymorphism) so it does not need
// to use the override keyword
protected void method2() {}
// Abstract method - subclasses of this class must implement this method
abstract Integer abstractMethod();
}
// Complete the abstract class by implementing its abstract method
public class ConcreteChildClass extends AbstractChildClass {
// Here we expand the visibility of the parent method - note that visibility
// cannot be restricted by a sub-class
public override Integer abstractMethod() { return 5; }
}
// A second sub-class of the original InnerClass
public class AnotherChildClass extends InnerClass {
AnotherChildClass(String s) {
// Explicitly invoke a different super constructor than one with no arguments
super(s);
}
}
// Exception inner class
public virtual class MyException extends Exception {
// Exception class member variable
public Double d;
// Exception class constructor
MyException(Double d) {
this.d = d;
}
// Exception class method, marked as protected
protected void doIt() {}
}
// Exception classes can be abstract and implement interfaces
public abstract class MySecondException extends Exception implements MyInterface {
}
}
此代码示例演示:
- 顶级类定义(也称为外部类)
- 顶级类中的静态变量和静态方法,作为 以及静态初始化代码块
- 顶级类的成员变量和方法
- 没有用户定义构造函数的类 — 这些类具有 隐式、无参数构造函数
- 顶级类中的接口定义
- 扩展另一个接口的接口
- 顶级类中的内部类定义(一级深度)
- 实现接口(因此,其关联的接口)的类 子接口)来实现方法签名的公共版本
- 内部类构造函数定义和调用
- 内部类成员变量以及使用关键字对它的引用(不带参数)this
- 一个内部类构造函数,它使用关键字(带参数)来 调用其他构造函数this
- 构造函数之外的初始化代码 — 其中 定义变量,以及大括号中的匿名块 ().请注意,这些执行 每个构造都按照它们在文件中出现的顺序出现,如 爪哇岛。{}
- 类扩展和抽象类
- 重写基类方法(必须声明)的方法virtual)
- 关键字 对于重写子类方法的方法override
- 抽象方法及其通过具体子类的实现
- 交通 修饰语protected
- 作为具有成员、方法和构造函数的第一类对象的异常
此示例演示其他 Apex 代码如何调用上述类:
// Construct an instance of an inner concrete class, with a user-defined constructor
OuterClass.InnerClass ic = new OuterClass.InnerClass('x');
// Call user-defined methods in the class
System.assertEquals(2, ic.method2(1));
// Define a variable with an interface data type, and assign it a value that is of
// a type that implements that interface
OuterClass.MyInterface mi = ic;
// Use instanceof and casting as usual
OuterClass.InnerClass ic2 = mi instanceof OuterClass.InnerClass ?
(OuterClass.InnerClass)mi : null;
System.assert(ic2 != null);
// Construct the outer type
OuterClass o = new OuterClass();
System.assertEquals(2, OuterClass.getInt());
// Construct instances of abstract class children
System.assertEquals(5, new OuterClass.ConcreteChildClass().abstractMethod());
// Illegal - cannot construct an abstract class
// new OuterClass.AbstractChildClass();
// Illegal – cannot access a static method through an instance
// o.getInt();
// Illegal - cannot call protected method externally
// new OuterClass.ConcreteChildClass().method2();
此代码示例演示:
- 外层阶级的构造
- 内部类的构造和内部类的声明 接口类型
- 可以为声明为接口类型的变量分配一个实例 实现该接口的类
- 将接口变量转换为实现 该接口(使用运算符验证后)instanceof
ref