It should also be added that most web wallets (one example is blockchain.info) encrypts the private key with your password. As the web wallet service does not store your password, your encrypted private key is secure, even if the web wallet service is hacked.
To put this in simpler terms:
Your private key is in essence just a number between 1 and 0xFFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFE BAAE DCE6 AF48 A03B BFD2 5E8C D036 4140 (slightly less than 2^256).
Lets say that the private key the web wallet service generates for you is 1012. In reality the number would of course be much bigger than this as randomly generating such a small number is extremely small. Lets say your password is "bbfh454!fdfK".
If you encrypt the number 1012 with the password "bbfh454!fdfK" the number 5056 is generated (this is only an example and not accurate). The same number (5056) will always be generated with the same password ("bbfh454!fdfK") starting from 1012. The number 5056 is your real private key which is used to access your wallet, but is never stored in the web wallet service database. The number is only generated when you log into your web wallet with your password.
Now lets say you instead try to encrypt the number 1012 with the password "qwerty". This time another number is generated, which could be 205. As 205 is not 5056, this password does not grant you access to the bitcoins in your wallet.
So for this reason no one can ever access your wallet without knowing your password, and no hacker can find out your password by hacking the web wallet service as they do not store your password.
One downside with this approach is that if you forget your password and have no backup of the wallet, your private key and also your bitcoin is gone forever.
Another downside is that this approach isn't secure if your hardware is infected with malware, as the specific malware can check which password you encrypt the private key with.
This feature was introduced with BIP38.