I remember having this issue when I first started game programming in Java. The issue is that when when you set the frame size, you are setting the size of the whole frame including the border so this will mess with your calculations. Also, the content pane is not considered when you call pack, only the components added to it are, so setting its size will not help you. With that in mind, here is a solution:
JPanel panel = new JPanel();
panel.setPreferredSize(new Dimension(800, 600));
This creates a JPanel which is like the content pane, and adds it to the frame. You can then render to the JPanel and not worry about your frame and its decorations.
The pack() method squeezes the window down to the minimum possible size while still allowing all of the components their requested sizes (this is what setPrefferedSize(Dimension dim) does). In other words, pack does not consider the content of your window, but rather the content of the contentPane, so unless something has been added, pack will hide everything but the border and title bar.
Also make sure you call pack AFTER adding your components and setting their preferred sizes, I made that mistake once and it took me forever to figure out what was wrong.
If you read https://fivedots.coe.psu.ac.th/~ad/jg/ch1/ch1.pdf
, I think you will have a better understanding of how this works, and a decent framework for a game.
Hope this helps.