The NIO API specifies two types of buffers: heap buffers and direct buffers. Heap buffers are buffers which wrap arrays. Generally, the "backing array" for such buffers is accessible indirectly via the ByteBuffer API. Heap buffers are characterized by fast access; however, they often cannot be used directly with channels (NIO generally copies the data of such buffers to and from direct buffers before performing I/O operations on them).
Direct buffers are buffers which are backed by memory allocated outside of the system heap - most often, as is the case when the ByteBuffer.allocateDirect() method is used, it is simply system heap memory. They have no "backing array" and are characterized by slower access because each access has to utilize special APIs (often involving a JNI bridge or an Unsafe method call) to transfer data to and from the memory region. Despite this, using direct buffers are much faster in certain cases because NIO can utilize them "directly" for I/O operations without introducing additional copies.
There is another variation on direct buffers: mapped buffers. These buffers have a special type (java.nio.MappedByteBuffer) and typically represent a mapping of a portion of a file into memory. Using such buffers as the source or target of read/write operations can, under some circumstances, perform much better than copying to and them from an intermediate buffer (of any type).