← Назад к вопросам

Что наследуется от Object?

1.0 Junior🔥 111 комментариев
#Dart#ООП и паттерны

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI26 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Что наследуется от 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.