There actually is an approach that can completely remove flickering, but it's a bit tricky, so I only tend to tell students about if if they ask.
The technique is known as "double-buffering", because it involves having an offscreen image (buffer) where you do all of your graphics work first, and then you use one command to draw that whole image onto your panel without clearing first.
Here's some example code, to show you how it works.
DrawingPanel panel = new DrawingPanel(800,600);
Graphics panelG = panel.getGraphics();
BufferedImage bufImage = new BufferedImage(800,600,
BufferedImage.TYPE_INT_RGB);
Graphics bufG = bufImage.getGraphics();
for (int i = 0; i < 100; i++) {
bufG.setColor(Color.WHITE);
bufG.fillRect(0, 0, 800, 600);
bufG.setColor(Color.BLACK);
bufG.fillOval(i*8, 0, 100, 100);
panelG.drawImage(bufImage, 0, 0, null);
panel.sleep(100);
}