Apex 类和 Java 类之间的差异

Apex 类和 Java 类的工作方式相似,但有一些重要的 差异。以下是 Apex 类和 Java 类之间的主要区别:

  • 内部类和接口只能在外部内部声明一个级别 类。
  • 静态方法和变量只能在顶级类中声明 定义,而不是在内部类中。
  • 内部类的行为类似于静态 Java 内部类,但不需要关键字。内部类可以 具有像外部类一样的实例成员变量,但没有隐式 指向外部类的实例的指针(使用 关键字)。staticthis
  • 访问修饰符是 default,并表示方法或变量只能在 定义它的 Apex 类。如果未指定访问修饰符,则 方法或变量是 。privateprivate
  • 不为方法或变量指定访问修饰符,并且访问修饰符是 同义。private
  • access 修饰符表示 方法或变量可以由此应用程序中的任何 Apex 使用,或者 命名空间。public
  • access 修饰符表示 方法或变量可以由任何有权访问该类的 Apex 代码使用, 而不仅仅是同一应用程序中的 Apex 代码。此访问修饰符应为 用于需要在应用程序外部引用的任何方法, 在 SOAP API 中或通过其他 Apex 代码。如果声明方法或 变量为 ,您还必须 将包含它的类声明为 。globalglobalglobal
  • 默认情况下,方法和类是最终的。
    • 定义修饰符 允许扩展和覆盖。virtual
    • 关键字必须是 显式用于重写基类方法的方法。override
  • 接口方法没有修饰符,它们始终是全局的。
  • 异常类必须扩展异常或其他用户定义的异常。
    • 他们的名字必须以单词 结尾。exception
    • 异常类有四个内置的隐式构造函数, 虽然你可以添加其他人。
  • 类和接口可以在触发器和匿名块中定义,但只能 作为本地人。

创建类定义

使用班级编辑器在 Salesforce 中创建班级。

  1. 在“设置”中,输入“快速” “查找”框,然后选择“Apex 类”。Apex Classes
  2. 单击“新建”。
  3. 单击“版本设置” 指定 Apex 的版本以及与此类一起使用的 API。 如果您的组织已从 AppExchange 安装托管软件包, 您还可以指定要与此一起使用的每个托管包的版本 类。对所有版本使用默认值。这会将 具有最新版本的 Apex 和 API 的类,以及每个托管的 包。您可以指定较旧的 托管包的版本(如果要访问组件或 与最新包版本不同的功能。你 可以指定旧版本的 Apex 和 API 来维护特定行为。
  4. 在类编辑器中,输入类的 Apex 代码。一个类可以启动 长度为 100 万个字符,不包括注释、测试方法或 使用 定义的类。@IsTest
  5. 单击保存”以保存更改并返回到课程 详细信息屏幕,或单击“快速保存”以保存更改 ,然后继续编辑您的课程。您的 Apex 类必须正确编译才能 您可以保存您的课程。

也可以通过单击 Generate 从 WSDL 自动生成类 来自 WSDL。请参阅 SOAP 服务:从 WSDL 文档定义类。

保存后,可以通过类方法或变量通过其他 Apex 代码调用类, 例如触发器。

注意

为了帮助向后兼容,类与 指定的 Apex 版本和 API。如果 Apex 类引用组件,例如 自定义对象,在已安装的托管包中,每个托管的版本设置 类引用的包也会被保存。此外,类使用一个标志进行存储,只要依赖元数据未更改,该标志就会设置为 因为该类是上次编译的。如果对对象名称或字段进行了任何更改 在类中使用的更改,包括表面更改,例如对对象的编辑或 字段说明,或者如果对调用此类的类进行了更改,则该标志将设置为 。当触发器或 Web 服务调用调用时 类,代码被重新编译,如果有任何错误,用户会收到通知。如果 没有错误,标志被重置 自。isValidtrueisValidfalseisValidtrue

Apex 类编辑器

Apex 和 Visualforce 编辑器具有以下功能:语法高亮显示编辑器会自动为关键字应用语法高亮显示,并且 所有函数和运算符。搜索 (search icon)通过搜索,可以在当前页面、类或 触发。若要使用搜索,请在“搜索”文本框中输入字符串,然后单击“查找” 下一步

  • 要将找到的搜索字符串替换为另一个字符串,请输入 “替换”文本框中的新字符串,然后单击“替换”以替换该字符串 实例,或“全部替换”来替换它 实例和出现的搜索字符串的所有其他实例 在页面、类或触发器中。
  • 若要使搜索操作区分大小写,请选择“匹配大小写”选项。
  • 若要使用正则表达式作为搜索字符串,请选择“正则表达式”选项。这 正则表达式遵循 JavaScript 的正则表达式 规则。使用正则表达式进行搜索可以找到 换行多行。如果使用替换操作 使用正则表达式找到的字符串,将 操作还可以绑定正则表达式组变量 (、 等)从 找到搜索字符串。例如,要将标签替换为标签,并保留所有 属性对原来完好无损,搜索并替换 它与.$1$2<h1><h2><h1><h1(\s+)(.*)><h2$1$2>

转到行 (Go to line arrow)此按钮允许您突出显示指定的行号。如果行 当前不可见,编辑器将滚动到该行。撤消 (Undo button) 和重做 (Redo button)使用撤消可撤消编辑操作,使用重做可重新创建编辑 已撤消的操作。字体大小从下拉列表中选择字体大小以控制 编辑器中显示的字符。行和列位置光标的行和列位置显示在状态中 编辑器底部的栏。这可以与转到行一起使用 (Go to line arrow) 至 快速浏览编辑器。行数和字符数行数和字符总数显示在状态栏中 在编辑器的底部。

命名约定

我们建议遵循 Java 标准 命名,即类以大写字母开头,方法以开头 使用小写动词,变量名称应该有意义。

定义具有相同名称的类和接口是不合法的 在同一个班级。内部阶级拥有也是不合法的 与其外部类同名。但是,方法和变量具有 它们在类中自己的命名空间,因此这三种类型的名称 不要相互冲突。特别是,对于变量来说,它是合法的, 方法,以及具有相同名称的类中的类。

名称阴影

成员变量可以被局部变量遮蔽,特别是 函数参数。这允许标准的方法和构造函数 Java 表单:

Public Class Shadow {
  String s;
  Shadow(String s) { this.s = s; } // Same name ok
  setS(String s) { this.s = s; } // Same name ok
}

一个类中的成员变量可以隐藏成员变量 父类中的相同名称。如果两个类 在不同的顶级班级,由不同的团队编写。 例如,如果一个人引用了 C 类并希望获得 访问父类 P 中的成员变量 M(同名 作为 C 中的成员变量),应将引用分配给引用 先到P。

静态变量可以在整个类层次结构中被隐藏,因此 如果 P 定义了一个静态 S,则子类 C 也可以声明一个静态 S。 C 中对 S 的引用是指该静态 – 以便引用 P中的那个,必须使用语法P.S。

静态类变量不能通过类实例引用。 它们必须单独使用原始变量名称(在 该顶级类文件)或以类名为前缀。例如:

public class p1 { 
  public static final Integer CLASS_INT = 1;
  public class c { };
}
p1.c c = new p1.c();
// This is illegal
// Integer i = c.CLASS_INT;
// This is correct
Integer i = p1.CLASS_INT;

命名空间前缀

Salesforce 应用程序支持使用命名空间前缀。命名空间前缀在托管 AppExchange 包中用于 将自定义对象和字段名称与其他对象和字段名称区分开来 组织。

重要

创建命名空间时,请使用有用且 为用户提供信息。但是,不要以人的名字命名命名空间(例如,通过 使用某人的姓名、昵称或私人信息)。分配命名空间后, 它们无法更改。

开发人员注册全局唯一的命名空间前缀并将其注册到 AppExchange 注册表,对自定义对象和字段名称的外部引用 开发人员的托管包采用以下长格式:

namespace_prefix__obj_or_field_name__c

这些完全限定的名称在工作 SOQL 或 SOSL 语句中更新可能很繁琐, 和 Apex 一旦一个类被标记为“托管”。因此,Apex 支持默认 命名空间用于架构名称。在查看标识符时,解析器假定 当前对象的命名空间是所有其他对象和字段的命名空间,除非 另有说明。因此,存储类必须引用自定义对象和字段 直接(使用 )为已定义的对象命名 在其相同的应用程序命名空间中。 obj_or_field_name__c

提示

仅在引用自定义对象时使用命名空间前缀 以及已从 AppExchange。

调用包方法时使用命名空间

若要调用托管包中定义的方法,Apex 允许完全限定 表单的标识符:

namespace_prefix.class.method(args)

版本化行为更改

在 API 版本 34.0 及更高版本中,自定义 SObjectType 上的 Schema.DescribeSObjectResult 包括以命名空间为前缀的映射键,即使命名空间是 当前正在执行的代码。如果您使用多个命名空间并生成运行时 描述数据,请确保您的代码使用命名空间正确访问密钥 前缀。

  1. 使用 System 命名空间
  2. 使用架构命名空间
    命名空间提供用于处理架构元数据信息的类和方法。我们隐式导入 ,但是当命名空间元素与非托管代码中的项发生命名冲突时,必须完全限定命名空间元素的使用。如果您的组织包含与 sObject 同名的 Apex 类,请在代码中将命名空间前缀添加到 sObject 名称中。SchemaSchema.*SchemaSchema
  3. 命名空间、类和变量名称优先级
  4. 类型的类型解析和系统命名空间

使用 System 命名空间

命名空间是 Apex 中的默认命名空间。这意味着您可以在创建新的命名空间时省略命名空间 系统类的实例或调用系统方法时。例如 因为内置的 URL 类在命名空间中,所以这两个语句都要创建一个 类的实例 是等效的:SystemSystemURL

System.URL url1 = new System.URL('https://MyDomainName.my.salesforce.com/');

和:

URL url1 = new URL('https://MyDomainName.my.salesforce.com/');

同样,要在类上调用静态方法,可以编写 以下内容:URL

System.URL.getCurrentRequestUrl();

艺术

URL.getCurrentRequestUrl();

注意

除了命名空间之外,命名空间中还有一个内置类, 它提供了类似 和 的方法。不要 对命名空间和类都具有这一事实感到困惑 在本例中为相同名称。和语句是等效的。SystemSystemSystemassertEqualsdebugSystem.debug(‘debug message’);System.System.debug(‘debug message’);

使用 System 命名空间消除歧义

在调用系统类的静态方法时,不包含命名空间更容易, 但在某些情况下,您必须包含命名空间才能区分 来自同名自定义 Apex 类的内置 Apex 类。如果您的组织包含您定义的 Apex 类,这些类的名称与内置类相同 类,则 Apex 运行时默认为您的自定义类,并调用 类。让我们看一下下面的例子。SystemSystem创造 此自定义 Apex 类:

public class Database {
    public static String query() {
       return 'wherefore art thou namespace?';
    }
}

在开发者控制台中执行以下语句:

sObject[] acct = Database.query('SELECT Name FROM Account LIMIT 1');
System.debug(acct[0].get('Name'));

执行语句时,Apex 首先在自定义类上查找查询方法。但是,这里的查询方法 class 不接受任何参数,因此找不到匹配项 出现错误。自定义类将重写命名空间中的内置类。 若要解决此问题,请在类名中添加命名空间前缀,以显式指示 Apex 运行时调用内置 Database 类上的查询方法 在命名空间中:Database.queryDatabaseDatabaseDatabaseSystemSystemSystem

sObject[] acct = System.Database.query('SELECT Name FROM Account LIMIT 1');
System.debug(acct[0].get('Name'));

使用 Schema 命名空间

命名空间提供类和 用于处理架构元数据信息的方法。我们隐式导入 ,但是当命名空间元素有命名冲突时,您必须完全限定对命名空间元素的使用 与非托管代码中的项一起使用。如果您的组织包含同名的 Apex 类 作为 sObject,将命名空间前缀添加到 s代码中的对象名称。

SchemaSchema.*SchemaSchema

在创建架构类的实例或调用 schema 方法。例如,由于 和 类位于命名空间中,因此这些代码 段是等效的。DescribeSObjectResultFieldSetSchema

Schema.DescribeSObjectResult d = Account.sObjectType.getDescribe();
Map<String, Schema.FieldSet> FSMap = d.fieldSets.getMap();

和:

DescribeSObjectResult d = Account.sObjectType.getDescribe();
Map<String, FieldSet> FSMap = d.fieldSets.getMap();

使用架构命名空间消除歧义

用于 引用与自定义类同名的 sObject。这种消歧义 指示 Apex 运行时使用 sObject。Schema.object_name

public class Account {
   public Integer myInteger;
}

// ...

// Create a standard Account object myAccountSObject
Schema.Account myAccountSObject = new Schema.Account();
// Create accountClassInstance, a custom class in your org
Account accountClassInstance = new Account();
myAccountSObject.Name = 'Snazzy Account';
accountClassInstance.myInteger = 1;

命名空间、类和变量名称优先级

因为局部变量、类名和命名空间都可以假设 使用相同的标识符,Apex 解析器以如下形式评估表达式:

name1.name2.[…].nameN

  1. 解析器首先假定这是一个局部变量,其中 – 作为 字段引用。name1name2nameN
  2. 如果第一个假设不成立,则解析器将假设 这是一个类名 并且是静态变量 带有 – 的名称作为字段引用。name1name2name3nameN
  3. 如果第二个假设不成立,则解析器假定 即命名空间 name,是类名,是静态变量名, 和 – 是字段引用。name1name2name3name4nameN
  4. 如果第三个假设不成立,则解析器报告 一个错误。

如果表达式以一组括号结尾(例如,),则 Apex 解析器将按如下方式计算表达式:

name1.name2.[…].nameM.nameN()

  1. 解析器首先假定它是本地 变量,其中 – 作为字段引用,并作为方法调用。name1name2nameMnameN
  2. 如果第一个假设不成立:
    • 如果表达式仅包含两个标识符 (),则解析器假定该标识符是类名,并且是方法调用。name1.name2()name1name2
    • 如果表达式包含两个以上的标识符,则解析器会假定该标识符是类名,是带有 – 作为字段引用的静态变量名称,并且是方法调用。name1name2name3nameMnameN
  3. 如果第二个假设不成立,则解析器假定是命名空间名称、类名、静态变量名称、 – 是字段引用, 并且是方法调用。name1name2name3name4nameMnameN
  4. 如果第三个假设不成立,则解析器将报告错误。

但是,对于类变量,Apex 还使用点表示法来引用成员变量。那些成员 变量可能引用其他类实例,也可能引用 添加到具有自己的点表示法规则来引用字段的 sObject 名称(可能导航外键)。

在表达式中输入 sObject 字段后,余数 的表达式保留在 sObject 域中,即 sObject 字段不能引用 Apex 表达式。

例如,如果您有以下类:

public class c { 
  c1 c1 = new c1(); 
  class c1 { c2 c2; } 
  class c2 { Account a; } 
}

那么以下表达都是合法的:

c.c1.c2.a.name
c.c1.c2.a.owner.lastName.toLowerCase()
c.c1.c2.a.tasks
c.c1.c2.a.contacts.size()

类型解析和系统命名空间 类型

因为类型系统必须解析定义的用户定义类型 在本地或其他类中,Apex 解析器按如下方式评估类型:

  1. 对于类型引用,解析器首先将该类型查找为标量类型。TypeN
  2. 如果未找到, 分析器查找本地定义的类型。TypeN
  3. 如果仍然不是 found,解析器将查找该名称的类。TypeN
  4. 如果仍然不是 found,解析器会查找系统类型,例如 sObjects。TypeN

对于以下类型 可能表示顶级类中的内部类型,也可能表示命名空间中的顶级类(按该优先级顺序)。

ref