Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Что наследуется от Object в Dart
Обзор
В Dart все классы наследуются от класса Object (прямо или косвенно). Это корень иерархии типов в Dart. При создании класса, даже если явно не указывается наследование, он автоматически наследует все методы и свойства от Object.
Основные методы Object
1. toString()
Возвращает строковое представление объекта.
class Person {
String name;
int age;
Person(this.name, this.age);
@override
String toString() => 'Person($name, age=$age)';
}
void main() {
final person = Person('Alice', 30);
print(person.toString()); // Person(Alice, age=30)
print(person); // Автоматически вызывает toString()
}
2. hashCode
Возвращает целое число, которое используется для оптимизации поиска в hash-таблицах (Set, Map).
class User {
final String id;
final String name;
User(this.id, this.name);
@override
int get hashCode => id.hashCode ^ name.hashCode;
}
void main() {
final user = User('1', 'Bob');
print(user.hashCode); // Некое число
final users = {user}; // Используется hashCode
}
3. operator ==(Object other)
Проверяет равенство объектов. По умолчанию использует сравнение по ссылке (identity).
class Point {
final int x;
final int y;
Point(this.x, this.y);
@override
bool operator ==(Object other) {
if (other is! Point) return false;
return x == other.x && y == other.y;
}
@override
int get hashCode => x.hashCode ^ y.hashCode;
}
void main() {
final p1 = Point(1, 2);
final p2 = Point(1, 2);
final p3 = p1;
print(p1 == p2); // true (значение)
print(p1 == p3); // true (одна и та же ссылка)
print(identical(p1, p2)); // false (разные объекты в памяти)
}
4. runtimeType
Возвращает тип объекта во время выполнения.
class Animal {}
class Dog extends Animal {}
void main() {
final dog = Dog();
print(dog.runtimeType); // Dog
Animal animal = dog;
print(animal.runtimeType); // Dog (реальный тип, не заявленный)
if (animal.runtimeType == Dog) {
print('This is a Dog!');
}
}
Важные особенности
Identity vs Equality
class Person {
String name;
Person(this.name);
@override
bool operator ==(Object other) =>
other is Person && name == other.name;
@override
int get hashCode => name.hashCode;
}
void main() {
final p1 = Person('John');
final p2 = Person('John');
print(p1 == p2); // true (equality)
print(identical(p1, p2)); // false (identity)
}
Правило: Если переопределяешь ==, переопредели и hashCode
Это критично для корректной работы с Set и Map:
// ПЛОХО - нарушит работу Set и Map
class BadPerson {
String name;
BadPerson(this.name);
@override
bool operator ==(Object other) =>
other is BadPerson && name == other.name;
// hashCode не переопределен!
}
// ХОРОШО
class GoodPerson {
String name;
GoodPerson(this.name);
@override
bool operator ==(Object other) =>
other is GoodPerson && name == other.name;
@override
int get hashCode => name.hashCode;
}
void main() {
final people = {GoodPerson('Alice'), GoodPerson('Alice')};
print(people.length); // 1 (корректно)
}
Использование в практике
Для Data Classes - используй equatable пакет
import 'package:equatable/equatable.dart';
class Product extends Equatable {
final int id;
final String name;
final double price;
Product(this.id, this.name, this.price);
@override
List<Object?> get props => [id, name, price];
}
void main() {
final p1 = Product(1, 'Book', 15.99);
final p2 = Product(1, 'Book', 15.99);
print(p1 == p2); // true
print({p1, p2}.length); // 1
}
В BLoC и Riverpod
class UserState extends Equatable {
final List<User> users;
final bool isLoading;
final String? error;
UserState({
required this.users,
required this.isLoading,
this.error,
});
@override
List<Object?> get props => [users, isLoading, error];
}
// Благодаря Equatable, BLoC корректно определит изменения состояния
Метод noSuchMethod()
Вызывается при обращении к несуществующему методу:
class DynamicObject {
@override
dynamic noSuchMethod(Invocation invocation) {
print('Вызван метод: ${invocation.memberName}');
return 'default';
}
}
void main() {
final obj = DynamicObject();
obj.nonExistentMethod(); // Вызван метод: nonExistentMethod
}
Вывод
Упонимание Object и его методов критично для:
- Корректной работы с коллекциями (Set, Map)
- Сравнения объектов
- Отладки
- Работы с BLoC и state management
- Создания правильных data classes
Основной паттерн: если переопределяешь ==, всегда переопредели hashCode.