This is the recommended style. Create an ordinary object in the usual way, and use its services.

Style 2 - variation on Style 1

List<Message> messages = new MessageDAO().fetchRecentMessages();

The DAO is created and used on the same line. This style seems a bit less legible than Style 1.

Style 3 - static methods

List<Message> messages = MessageDAO.fetchRecentMessages();

Probably the least desirable. One must exercise care that such classes are
thread-safe. This issue usually doesn't exist in Styles 1 and 2, if the DAO
has no static members, is short-lived, and there is no possibility of sharing data between threads.

Full DAO Design Pattern

It's common to describe Data Access Objects as
an extended design pattern.
That design pattern centers on allowing wholesale changes to a datastore mechanism - for
example, changing from a relational database to using the file system, or some other means of data storage.
It is only required when multiple storage mechanisms must coexist during production, or when
the details of how data is to be stored is decided during deployment.

It must be stressed that most applications do not need the full DAO design pattern
as usually described. Most business applications are deployed with
a very particular database in mind. In such cases, allowing a deployer
to configure various types of datastore seems entirely superfluous.
If your application won't benefit from it, then the full DAO pattern is clearly of dubious benefit.
Rather, implementing each DAO as a single, ordinary class seems more appropriate and effective.