For simple DAOs, various implementation styles are possible:
Style 1 - instance methods
MessageDAO dao = new MessageDAO();
List<Message> messages = dao.fetchRecentMessages();
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.