Web applications, broadly, are bodies of software that provide useful functionality and information to clients over HTTP and other World Wide Web protocols. This means getting a lot of leverage out of a simple protocol. HTTP is connectionless, making multi-phase conversations between client and Web application tricky. HTTP's GET method supports only the crude CGI parameter string as a means of client expression.
Java Servlets are classes implemented to a contract, similar in a way to the EJB contract in that there is a component-container relationship. The container is the Web server, which to be servlets-compliant must load and instantiate servlet classes according to a standard deployment descriptor (an XML document), call certain methods on these instances to represent HTTP(S) requests, and provide responses to the client based on the actions of the servlets. The container manages the servlet's lifecycle, and, again similarly to EJB, can pool servlets and even support clustering over multiple machines. Again, the idea is to take the boilerplate stuff away and leave the servlet class with the application-specific responsibilities.