Layered is usually like this (arrow indicates a dependency):
Data <-- UI
Which split apart a bit more can become:
Data <-- Logic <-- UI
Hexagonal uses dependency inversion to achieve:
Data --> Logic <-- UI
And further:
Database --> |-------| <-- CLI
Resources --> | Logic | <-- Desktop GUI
Files --> |-------| <-- Web UI
The modules on the left are called "driven" and simply respond to requests. The modules on the right are called "drivers" and are where requests are generated. Everything goes through the Logic which is the business rules of the system written in pure dependency-free code. The Logic becomes the language of the system that any of the parts can use to communicate with the other parts.
This sounds amazing, and it is, though it can be a bit more tricky to implement than this sounds. But at the same time, I find everything has a tendency to fall into place; everything has a clear place to live.
In the Data <-- Logic <-- UI
setup, I found that the code in "Logic" never made sense to put anywhere in particular. It could go in any of the three places and still never felt right. This is because it was still really database code, and since the UI knew about the database, database code could still go right in the UI. Or it could go in the Data layer. Or it could go in the "Logic" layer.
With Hexagonal, all dependency is filtered out of your Logic like a sieve, leaving only pristine dependency-free Logic code left over. You now want to put as much code as you can in the Logic module, because just by putting it there you remove its dependencies and make it more reusable.