句柄类和值类的比较
基本差异
值类构造函数返回一个与其赋值变量相关联的对象。如果对此变量重新赋值,MATLAB® 会创建原始对象的独立副本。如果将此变量传递给函数以修改它,函数必须将修改后的对象以输出参数形式返回。
句柄类构造函数返回句柄对象,该对象是对所创建对象的引用。可以将句柄对象赋给多个变量或将它传递给函数,而不会导致 MATLAB 创建原始对象的副本。函数对作为输入参数传递的句柄对象进行修改后,不必返回该对象。
所有句柄类都派生自抽象的 handle 类。
创建值类
默认情况下,MATLAB 类是值类。以下定义创建名为 MyValueClass 的值类:
classdef MyValueClass
...
end
创建句柄类
要创建handle类,请从handle类派生该类。
classdef MyHandleClass < handle
...
end
MATLAB 内置类的行为
MATLAB 基础类是值类(数值、logical、char、cell、struct 以及函数句柄)。例如,如果创建 int32 类的对象并复制该对象,结果会是两个独立的对象。更改a的值不会导致b的值发生更改。此行为是表示值的类的典型行为。
a = int32(7);
b = a;
a = a^4;
b
7
MATLAB 图形对象作为句柄对象实现,因为它们表示视觉元素。例如,创建一个图形线条对象,并将它的句柄复制到另一个变量。这两个变量引用同一个线条对象。
x = 1:10; y = sin(x);
l1 = line(x,y);
l2 = l1;
使用句柄的任一副本设置线条对象的属性。
set(l2,'Color','red')
set(l1,'Color','green')
get(l2,'Color')
ans =
0 1 0
对 l2 句柄调用 delete 函数会销毁该线条对象。如果尝试在 l1 行设置 Color 属性,set 函数将返回错误。
delete(l2)
set(l1,'Color','blue')
Error using matlab.graphics.primitive.Line/set
Invalid or deleted object.
如果通过删除任一现有句柄来删除对象,则所有副本都将变为无效,因为删除了被所有句柄引用的单个对象。
删除句柄对象不同于清除句柄变量。在图形对象层次结构中,对象的父级保存对该对象的引用。例如,父坐标区包含对 l1
和 l2
引用的线条对象的引用。如果从工作区中清除这两个变量,该对象仍然存在。
有关句柄对象行为的详细信息,可以参考句柄对象行为。
用户定义的值类
MATLAB 将值类的对象与该对象的赋值变量相关联。当将值对象复制到另一个变量或将值对象传递给函数时,MATLAB 会创建该对象和该对象包含的所有数据的独立副本。对原始对象的更改不会影响到新对象。值对象的行为类似于 MATLAB 数值类和 struct 类。每个属性的行为本质上都类似于 MATLAB 数组。
值对象始终与一个工作区或临时变量相关联。当值对象的变量超出作用域或被清除时,值对象会超出作用域。此处没有对值对象的引用,只有作为独立对象的副本。
值对象行为
以下是一个值类,它在其 Number 属性中存储一个值。默认属性值是数字 1。
classdef NumValue
properties
Number = 1
end
end
创建一个为变量 a 赋值的 NumValue 对象。
a = NumValue
a =
NumValue with properties:
Number: 1
将 a 的值赋给另一个变量 b。
b = a
b =
NumValue with properties:
Number: 1
变量 a 和 b 是独立的。更改 a 的 Number 属性的值不会影响 b 的 Number 属性。
a.Number = 7
a =
NumValue with properties:
Number: 7
b
b =
NumValue with properties:
Number: 1
修改函数中的值对象
将值对象传递给函数时,MATLAB 会在函数工作区中创建该对象的副本。由于值对象的副本是独立的,因此函数不会修改调用方工作区中的对象。因此,修改值对象的函数必须返回修改后的对象,用以在调用方工作区中重新赋值。具体可以参考对象修改。
用户定义的句柄类
从 handle 类派生的类的实例是对底层对象数据的引用。复制句柄对象时,MATLAB 会复制句柄,但不会复制存储在对象属性中的数据。副本引用与原始句柄相同的对象。如果更改原始对象的属性值,复制的句柄将引用相同的更改。
句柄对象行为
以下是一个句柄类,它在 Number 属性中存储一个值。默认属性值是数字 1。
classdef NumHandle < handle
properties
Number = 1
end
end
创建一个为变量 a 赋值的 NumHandle 对象。
a = NumHandle
a =
NumHandle with properties:
Number: 1
将 a 的值赋给另一个变量 b。
b = a
b =
NumHandle with properties:
Number: 1
变量 a 和 b 引用同一底层对象。更改 a 的 Number 属性的值也将更改 b 的 Number 属性的值。即,a 和 b 引用同一个对象。
a.Number = 7
a =
NumHandle with properties:
Number: 7
b
b =
NumHandle with properties:
Number: 7
修改函数中的句柄对象
当将句柄对象传递给函数时,MATLAB 会在函数工作区中创建句柄的副本。由于句柄的副本引用相同的底层对象,因此修改句柄对象的函数实际上也会修改调用方工作区中的对象。因此,函数对作为输入参数传递的句柄对象进行修改后,不必将修改后的对象返回给调用方。
删除句柄
可以通过显式调用句柄的 delete 方法来销毁句柄对象。删除句柄类对象的句柄会使所有句柄无效。例如:
a = NumHandle;
b = a;
delete(a)
b.Number
Invalid or deleted object.
对句柄对象调用 delete 会调用该对象的析构函数。具体可以参考句柄类析构函数。
确定对象的相等性
值对象的相等意味着这些对象属于同一个类并且具有相同的状态。
句柄对象的相等意味着句柄变量引用同一个对象。还可以识别引用同一类且具有相同状态的不同对象的句柄变量。
值对象的相等性
要确定值对象是否大小相同且内容等值,请使用 isequal。例如,使用先前定义的 NumValue 类创建两个实例并测试相等性:
a = NumValue;
b = NumValue;
isequal(a,b)
ans =
1
a 和 b 是独立的,因此不是同一个对象。然而,二者都表示相同的值。如果更改由一个值对象表示的值,这些对象将不再相等。
a = NumValue;
b = NumValue;
b.Number = 7;
isequal(a,b)
ans =
0
值类没有默认的 eq 方法来实现 == 运算。
句柄对象的相等性
句柄对象从 handle 基类继承 eq 方法。可以使用 == 和 isequal 测试句柄对象之间的两种不同关系:
-
句柄引用同一个对象:== 和 isequal 返回 true。
-
句柄引用同一类且具有相同值的对象,但它们不是同一对象 - 只有 isequal 返回 true。
使用先前定义的 NumHandle 类创建对象并复制句柄。
a = NumHandle;
b = a;
使用 == 和 isequal 测试相等性。
a == b
ans =
1
isequal(a,b)
ans =
1
使用默认值创建 NumHandle 类的两个实例。
a = NumHandle;
b = NumHandle;
确定 a 和 b 是否引用同一个对象。
a == b
ans =
0
确定 a 和 b 是否具有相同的值。
isequal(a,b)
ans =
1
句柄类支持的功能
从 handle 类派生的类能够:
-
继承多个有用的方法(Handle Class Methods)
-
定义事件和侦听程序(事件和侦听程序语法)
-
定义动态属性(动态属性 - 向实例添加属性)
-
实现 set 和 get 方法(为属性实现 set/get 接口)
-
自定义复制行为(Implement Copy for Handle Classes)