句柄类和值类的比较
基本差异
值类构造函数返回一个与其赋值变量相关联的对象。如果对此变量重新赋值,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
会调用该对象的析构函数。有关详细信息,请参阅 句柄类析构函数。
初始化属性以包含句柄对象
有关在属性代码块中将属性初始化为默认值和在构造函数中初始化属性之间区别的信息,请参阅Initialize Property Values和Initialize Arrays of Handle Objects。
确定对象的相等性
值对象的相等意味着这些对象属于同一个类并且具有相同的状态。
句柄对象的相等意味着句柄变量引用同一个对象。您还可以识别引用同一类且具有相同状态的不同对象的句柄变量。
值对象的相等性
要确定值对象是否大小相同且内容等值,请使用 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)
有关句柄类及其方法的详细信息,请参阅The Handle Superclass。