#dart
Вопрос:
У меня есть класс B, расширяющий класс A, и у него метод toJSON переопределяет метод toJSON класса A. Но когда я переношу класс B в класс A, метод toJSON не будет изменен с класса B на класс A.
class A {
String str1;
A(this.str1);
Map<String, dynamic> toMap() => {
'str1': str1,
}
}
class B extends A {
String str2;
B(this.str2, str1) : super(str1);
Map<String, dynamic> toMap() => {
'str2': str2,
'str1': str1,
}
}
void test(A a) {
print(a.toMap());
}
// When I pass class B in class A parameter, it still use the class B.toMap method.
B b = B('str2', 'str1');
test(b);
Ответ №1:
Все методы экземпляра Dart являются виртуальными, также известными как динамическая отправка. Это означает , что при вызове a.toMap()
, какая toMap
реализация вызывается, зависит от типа среды выполнения объекта a
, а не от статического типа выражения a
.
Итак, в данном случае вы вызываете toMap
экземпляр B
, поэтому вы используете B
«s toMap
«.
Это довольно распространенное поведение в объектно-ориентированных языках (динамическая отправка-одна из отличительных особенностей объектной ориентации: объект определяет, как реагировать на отправленное вами сообщение, здесь запрос на выполнение операции «toMap».)
Некоторые объектно-ориентированные языки также имеют невиртуальные методы. Дарт этого не делает. Вы можете либо определить статический метод:
class A {
static Map<String, dynamic> toMap(A value) => ...;
}
class B {
static Map<String, dynamic> toMap(B value) => ...;
}
а затем выберите, кому из них позвонить:
print(A.toMap(a));
или вы можете использовать методы расширения (которые на самом деле являются просто статическими методами с более приятным синтаксисом вызова), потому что они отправляют на основе статического типа получателя:
extension AToMap on A {
Map<String, dynamic> toMap() => ...;
}
extension BToMap on B {
Map<String, dynamic> toMap() => ...;
}
и называйте это нормально:
print(a.toMap()); // Chooses AToMap.toMap based on static type of `a`.
В большинстве ситуаций, если вы действительно хотите получить доступ и A.toMap
к тому , и B.toMap
к другому экземпляру B
, вам лучше переименовать один из методов, чтобы избежать конфликта имен.