The difference is really one of when things (can/might) get executed.
A ServletContext Listener will be invoked as soon as possible after the servlet context is created. This is almost always when the server starts up, although it can also be when a whole servlet container or web application is reinitialised for some reason.
The "init" method of a servlet, on the other hand, is only guaranteed to be called after a particular servlet has been loaded but before it serves any requests.
Servlet containers are free to "init" all servlets at the start, defer running "init" until the first request comes in for that servlet, or any time between these two events.
So. If you definately need your code to execute when the container starts,
you should use a servlet lifecycle listener. If you just need to make sure your code has already been executed before a request has been processed, but don't really care when it is done otherwise, put your code in "init".
Has that helped?