В чем разница между внедрения зависимостей и наследованием?
Если честно, то это принципиально разные вещи.
Есть принципы ООП - наследование, абстракция, инкапсуляция, полиморфизм.
Наследование (inheritance):
{class} extends {superClass} это способность класса или объекта базироваться на другом классе или объекте.
Например, Dog -> Animal  Cat -> Animal

Внедрение зависимостей (dependency injection) является разновидностью IoC (inversion of control - инверсия управления). Например, есть класс, внутри которого есть объект для подключения к БД. Притом connection является интерфейсом. То какая реализация в зависимости от используемой БД будет внедрена во время рантайма на данный момент не определена.
UserService {
Connection connection;
}

Т.е. если разработчик хочет подключить БД MySQL, то будет внедрена реализация connection для работы с MySQL. Например, MySqlConnection
Т.е. класс UserService не решает какая именно зависимость должна быть внедрена туда. За него это делает отдельный механизм согласно конфигурации.

Я привел абстрактные примеры, чтобы лучше была видна разница между DI & inheritance
Тут как и везде в ООП, вопрос не технический а скорее филосовский. Ваш вопрос наверное лучше задать как - "В чем разница между наследованием и композицией, ведь при композиции мы так же получаем доступ к методам и полям класса". Разница в том, что при наследовании класс становится прямым потомком некоего класса, при композиции данный класс становится частью нашего класса, при этом "родственных связей" между ними нет.
Ну например было бы логично такое наследование Engine -> Car ? Не думаю. А вот внедрить через зависимость ту же, сделать композицию обьектов, сделать движок частью машины, но не его наследником - это уже логично, это то как мы себе представляем реальный мир.