Check this code for your reference
ContentNote contentNote = new ContentNote();
contentNote.Title = 'First Note';
// You can pass html type text here for rich text formatted text
String body = '<b>This is my first note</b>';
contentNote.Content = Blob.valueOf(body);
insert contentNote;
ContentDocumentLink link = new ContentDocumentLink();
link.ContentDocumentId = contentNote.id;
link.LinkedEntityId = '001J2000009E7XD';
link.ShareType = 'I';
link.Visibility = 'AllUsers';
insert link;
Basically in ContentNote record you specify the enhanced note content that you want to add. Here you can specify title and the rich text formatted body of that enhanced note.
Since a single record can have multiple enhanced notes and also a single note can be related to multiple records by sharing, a junction object named ContentDocumentLink exist between the two to establish this many to many relation.
Here in LinkEntityId field you specify the record Id for which you want to create the enhanced note.
Visibility field determines who all can have access to this note and ShareType determines what access they will have on this note
Visibity field can have below values
And shareType can have below values.
Here one thing you may notice is though ContentDocumentId is a lookup to ContentDocument Object, providing contentNote Id still works and doesnt causes error .Basically right after contentNote record is created, Salesforce creates contentDocument record in background with Id same as this contentNote record
You can check this by running this query
Select Id,Description,FileExtension,FileType,SharingPrivacy,Title from ContentDocument where Id =: contentNote.Id
Since both have same Id value you dont need to explicitly query contentDocument record and instead can directly provide contentNote Id.