Dependency injection is a design pattern that removes tight coupling between objects and their dependencies. It allows for objects to have their dependencies satisfied externally rather than internally. There are three main types of dependency injection: constructor injection, setter injection, and interface injection. Constructor injection passes dependencies through a class's constructor, while setter injection uses properties, and interface injection relies on implementing a common interface. Dependency injection promotes loose coupling, testability, and flexibility between classes.