Welcome to the Ranch.
Hooks, inversion of control and dependency injection are not exactly the same thing, but there is some relation between these terms.
When you write a simple program, then often your program has a main loop somewhere, that for example does something like this: (1) wait for input, (2) process the input and produce output, (3) go back to step 1. The main loop is the main path of control of what the program does.
Inversion of control means that you don't program the main loop yourself, but that you instead let some existing software framework do that for you. You give the framework one or more callback methods (hooks), and the framework will call them whenever some event happens. It's called "inversion of control" because the main control loop is now in a framework or library instead of in your own code - instead of your own code calling library methods, you let the library call your code (hence, "inversion").
Depencency injection is slightly different. When you write a program, it often consists of different components working together. To make the program work, you need to connect these components together. The simple way to do this is, is to just instantiate the component that you need using the 'new' operator. For example, suppose that your program needs to interact with a database. You could create a class that does all the database interaction, and in your main program class you create a new instance of this database class, and you call methods on it to work with the database.
The problem with that approach is that you tightly couple the main program class to the database class. Suppose that at some point you decide that you want to use some other database, for which you create a second implementation of the database class. You would need to modify the main program too if you want to use the other database class.
With dependency injection you let some framework handle connecting the components of the program together. If you use the Spring framework, for example, you can use annotations, something like this:
You then tell the Spring framework to resolve the dependencies, and it will automatically initialize in the variable 'database' in MainProgram with a new instance of OracleDatabase.
The coupling between MainProgram and Database is now not so tight, and you can easily let Spring insert something else than an OracleDatabase by configuring Spring differently. For example, for
testing, you can insert a mock database object instead of the real one.