Skip to content

Latest commit

 

History

History
135 lines (91 loc) · 5.75 KB

2.3.类实例.md

File metadata and controls

135 lines (91 loc) · 5.75 KB

2.3.类实例

和许多面向对象语言类似,类是大多数 Haxe 程序中主要的数据结构。每个 Haxe 类都有一个确定的名字,一个隐含的路径和零或者多个类字段。这里我们将关注类的一般结构及它们之间的关系,而 类字段(第4章) 的详细内容将在之后展开。

以下代码示例作为本节剩余部分的基础:

class Point { 
    var x : Int; 
    var y : Int;
    public function new(x,y) { 
        this.x = x;
        this.y = y; 
    }
    public function toString() { 
        return "Point("+x+","+y+")";
    }
} 

从语义上讲,这个类表示二维空间内的一个点,但是这里它是什么并不重要。我们来描述一下这个结构:

  • 关键字 class 表示我们定义一个类
  • Point 是类的名称,可以使用任何符合类型标识符规则的字符
  • 包围在花括号 {} 中间的是类的字段
  • 它由两个 Int 类型变量字段 xy 组成
  • 后面是一个特定的函数字段叫做 new ,它是类的构造函数
  • 还有一个普通的函数 toString

在 Haxe 中有一个特殊类型,可以兼容所有的类:

类型 :Class 这个类型可以兼容所有类型,也就是说,所有类(而不是它们的实例)可以被分配给它。在编译时,Class 是所有类的基础类型。然而,这个关系并不会反映在生成的代码中。当一个 API 需要的一个值是一个类而非某个特定的类型时,可以使用这个类型。这应用到 Haxe 反射API (第10.7节) 中的一些方法。

2.3.1.类的构造函数

类的实例通过调用类的构造函数(一个通常称为实例化的过程)创建。类实例的另一个称呼叫做对象。然而,我们更倾向于使用术语“类的实例”来强调 类/类实例 及 枚举/枚举实例(第2.4节)之间的类比。

var p = new Point(-1, 65);

这会生成一个 Point 类的实例,它被分配到一个变量 p 上。Point 的构造函数接受两个参数 -165,然后分别分配它们到实例变量 xy(对比在 类实例(第2.3节) 中它的定义)。我们将在 new(第5.12节) 中重新审视 new 表达式的精确意思。现在,只要把它当作调用类的构造函数并返回适当的对象。

2.3.2.继承

类可以继承自其它的类,在 Haxe 中通过 extends 关键字指示:

class Point3 extends Point {
    var z : Int;
    public function new(x,y,z) {
        super(x,y);
        this.z = z; 
    } 
}

这个关系通常被称为 “is-a”(subsumption,包含架构,指的是类的父子继承关系):任何 Point3 类的实例同时也是 Point 类的实例。Point 则作为 Point3 的父类,而 Point3 则是 Point 的子类。一个类可以被许多子类继承,但是只能继承一个父类。术语 “某个类的父类” 通常指它的直接父类、父类的父类,以此类推。

上面的代码和原来的 Point 类很相似,使用了两个新的部分:

extends Point 表示这个类继承自 Point 类。 super(x, y) 是调用父类的构造函数,本例中即 Point.new

在子类中定义它们自己的构造函数并不是必须的,但是如果定义了,则调用 super() 是必须的。不像其它一些面向对象语言,这个调用可以出现在构造函数代码中的任何地方,而不必作为构造函数中的第一个表达式。

一个类可以重写它父类的 方法(第4.3节),需要显式使用的 override 关键字。效果和限制将在 重写方法(第4.3.1节) 中详细介绍。

2.3.3.接口

一个接口可以被理解为一个类的签名,因为它描述了一个类的公共字段。接口不提供实现,而是单纯地提供结构化信息:

interface Printable {
    public function toString():String;
} 

语法和类的相似,但有以下例外:

  • 使用 interface 关键字而不是 class 关键字
  • 函数不含有任何表达式
  • 每个字段必须有一个显式的类型声明

接口不像 结构化子类型(第3.5.2节),它只描述与类之间的一个静态关系。一个给定的类只有当如下描述时才被认为是与给定接口兼容的:

class Point implements Printable { }

这里,implements 关键字表示 Point “是一个” Printable ,即每个 Point 的实例同时也是 Printable 接口的实例。虽然一个类只能有一个父类,但是它可以通过使用多个 implements 关键字实现多个接口:

class Point implements Printable 
    implements Serializable 

编译器会确保 implements 的假设成立。也就是说,它会确保类实现了接口所需的所有字段。当一个类或该类的父类中提供了该字段的实现时,该字段才被认为是已实现的。

接口的字段不仅限于方法,也可以是变量或者属性:

interface Placeable { 
    public var x:Float; 
    public var y:Float; 
}

class Main implements Placeable {
    public var x:Float;
    public var y:Float; 
    static public function main() { }
} 

接口可以通过使用 extends 关键字继承多个别的接口:

interface Debuggable extends Printable extends Serializable

Haxe 4.0.0 开始:

像类一样,接口也可以通过 final 关键字进行修饰以避免接口被其他接口扩展。

花絮:实现的语法 Haxe 3.0 之前 需要多个 implements 关键字并使用逗号 , 进行分隔。我们决定遵循 Java 事实上的标准,免除了逗号。这也是 Haxe 2 和 Haxe 3 之间的一个断层式的变更。