В большинстве случаев оба метода ведут себя одинаково, и выбор - это всего лишь предпочтение, в зависимости от того, что вам кажется более понятным / простым в обслуживании и т. Д.
Но они не одинаковы, и в некоторых случаях вы попадете в беду, если не будете знать о различиях.
Существенным отличием является то, что свойства, которые инициализируются в конструкторе, инициализируются отдельно при каждом построении объекта, тогда как свойства, которые инициализируются в блоке свойств значением по умолчанию, инициализируются один раз, когда определение класса впервые читается. Значением по умолчанию в блоке свойств является значение по умолчанию class , а не объекта; и (используя отражение) вы можете запросить это значение по умолчанию, даже если ни один экземпляр класса еще не был создан.
В большинстве случаев это не имеет значения - но когда начальное значение является объектом-дескриптором или выводом неопределенной функции, это делает. Итак, рассмотрим следующие два класса:
classdef A
properties
foo
end
methods
function obj = A
obj.foo = containers.Map;
end
end
end
classdef B
properties
foo = containers.Map
end
end
Обратите внимание, что containers.Map
является классом дескриптора.
В классе A
каждый раз, когда вы создаете новый экземпляр A
, вы получаете новый / другой containers.Map
для его foo
. В B
каждый экземпляр B
получает одинаковые containers.Map
для своих foo
, поскольку свойство инициализируется только один раз, при первом чтении определения класса. Поэтому, если вы измените foo
для любого объекта класса B
, это изменение распространяется на все другие экземпляры класса B
, как вы можете видеть:
>> a1 = A; a2 = A; a1.foo('greeting') = 'hello'; a2.foo('greeting') = 'bonjour';
>> a1.foo('greeting'), a2.foo('greeting')
ans =
'hello'
ans =
'bonjour'
>> b1 = B; b2 = B; b1.foo('greeting') = 'hello'; b2.foo('greeting') = 'bonjour';
>> b1.foo('greeting'), b2.foo('greeting')
ans =
'bonjour'
ans =
'bonjour'
>> % Note that b1.foo has changed as a result of setting b2.foo
Этот пункт о классах обработки, так как значения по умолчанию часто сбивают людей с толку; но поведение не специфично для обработки классов. Например, рассмотрим следующий вариант:
classdef A
properties
foo
end
methods
function obj = A
obj.foo = datetime('now');
end
end
end
classdef B
properties
foo = datetime('now')
end
end
Здесь A
будет хранить время создания каждого объекта, тогда как B
будет хранить время, когда класс был впервые инициализирован, для всех объектов, независимо от того, когда они были созданы.
Если вы считаете, что это поведение сбивает с толку, см. https://undocumentedmatlab.com/blog/handle-object-as-default-class-property-value, и, в частности, ветку комментариев под этой статьей, для обсуждения проблемы и объяснения причин, по которым MATLAB разработан таким образом.
Редактировать: Замечательный вопрос в комментариях, касающийся поведения clear
и его отношения к этой проблеме.
Используя вторую реализацию классов выше (с datetime
), посмотрите на следующее:
>> a = A; b = B; datestr(a.foo), datestr(b.foo)
ans =
'01-Sep-2018 18:59:30'
ans =
'01-Sep-2018 18:59:30'
>> clear variables
>> a = A; b = B; datestr(a.foo), datestr(b.foo)
ans =
'01-Sep-2018 18:59:48'
ans =
'01-Sep-2018 18:59:30'
>> clear classes
>> a = A; b = B; datestr(a.foo), datestr(b.foo)
ans =
'01-Sep-2018 18:59:57'
ans =
'01-Sep-2018 18:59:57'
Итак, прежде всего мы создаем A
и B
и отображаем их foo
s, и они оба показывают одинаковое время. Затем мы немного подождем, сделаем clear variables
и сделаем это снова. Обратите внимание, что foo
с A
- это новое время, а foo
с B
остается таким же, как и раньше. Наконец, мы ждем немного больше времени, мы делаем clear classes
, и мы делаем это снова. На этот раз у A
и B
есть новое время.
Почему? Потому что clear variables
просто удаляет ссылки на переменные из рабочей области. Определение класса B
не очищается, поэтому, когда мы создаем еще один B
, он по-прежнему использует значение с момента, когда определение класса было впервые прочитано. clear classes
, напротив, также удаляет определение класса , поэтому, когда мы позже создаем новый B
, он получает это время, поскольку определение класса затем перечитывается. Все это не имеет отношения к A
, поскольку foo
только что дали значение во время строительства.
Обратите внимание, что clear classes
очищает все определения классов: вы можете очистить определение только класса B
, используя clear B
.