Following the question Connecting to the server which password contains "@" symbols using ftp protocol, the answer is right. URLEncoder encodes @ into %. But let's say password already contains % and I am not encoding it, then how URL class will get to know that password in not encoded one?
The browser (or method that is parsing the FTP URL) is URL Decoding the password. So if you don't URL Encode the password and you pass a % it will attempt to decode it anyways and therefor won't work. The same thing applies to @ and :. This answer over on Super User includes more detailed proof that this is in fact what is happening (they inspected the raw TCP/IP traffic with Wireshark to see what was being passed).